mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Updated editor to v0.10.7
This commit is contained in:
@@ -17,9 +17,5 @@
|
||||
|
||||
package com.itsaky.androidide.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class BooleanEditor extends BaseValueEditorFragment {
|
||||
|
||||
}
|
||||
/** @author Akash Yadav */
|
||||
public class BooleanEditor extends BaseValueEditorFragment {}
|
||||
@@ -42,133 +42,130 @@ import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
/** @author Akash Yadav */
|
||||
public class DimensionEditor extends BaseValueEditorFragment {
|
||||
|
||||
private static final Logger LOG = Logger.instance ("DimensionEditor");
|
||||
|
||||
private static final Logger LOG = Logger.instance("DimensionEditor");
|
||||
public TextWatcherAdapter dimensionInputWatcher;
|
||||
public TextWatcherAdapter dimensionResInputWatcher;
|
||||
private LayoutDimensionAttrEditorBinding binding;
|
||||
private String[] dimensionUnits;
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView (
|
||||
public View onCreateView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
this.binding = LayoutDimensionAttrEditorBinding.inflate (inflater, container, false);
|
||||
return this.binding.getRoot ();
|
||||
this.binding = LayoutDimensionAttrEditorBinding.inflate(inflater, container, false);
|
||||
return this.binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated (view, savedInstanceState);
|
||||
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final var dimensionInput =
|
||||
Objects.requireNonNull (this.binding.dimensionInput.getEditText ());
|
||||
Objects.requireNonNull(this.binding.dimensionInput.getEditText());
|
||||
if (dimensionInputWatcher != null) {
|
||||
dimensionInput.removeTextChangedListener (dimensionInputWatcher);
|
||||
dimensionInput.removeTextChangedListener(dimensionInputWatcher);
|
||||
}
|
||||
|
||||
|
||||
dimensionInputWatcher =
|
||||
new TextWatcherAdapter () {
|
||||
new TextWatcherAdapter() {
|
||||
@Override
|
||||
public void afterTextChanged (@NonNull Editable s) {
|
||||
final var text = s.toString ().trim ();
|
||||
public void afterTextChanged(@NonNull Editable s) {
|
||||
final var text = s.toString().trim();
|
||||
final var unit =
|
||||
getDimensionUnits ()[binding.unitSelector.getSelectedItemPosition ()];
|
||||
|
||||
getDimensionUnits()[binding.unitSelector.getSelectedItemPosition()];
|
||||
|
||||
// This will call CommonParseUtils#parseDimension
|
||||
notifyValueChanged (text.concat (unit));
|
||||
notifyValueChanged(text.concat(unit));
|
||||
}
|
||||
};
|
||||
|
||||
dimensionInput.addTextChangedListener (dimensionInputWatcher);
|
||||
|
||||
|
||||
dimensionInput.addTextChangedListener(dimensionInputWatcher);
|
||||
|
||||
final var dimensionResInput =
|
||||
(MaterialAutoCompleteTextView)
|
||||
Objects.requireNonNull (binding.dimensionResInput.getEditText ());
|
||||
|
||||
Objects.requireNonNull(binding.dimensionResInput.getEditText());
|
||||
|
||||
if (dimensionResInputWatcher != null) {
|
||||
dimensionResInput.removeTextChangedListener (dimensionResInputWatcher);
|
||||
dimensionResInput.removeTextChangedListener(dimensionResInputWatcher);
|
||||
}
|
||||
|
||||
|
||||
dimensionResInputWatcher =
|
||||
new TextWatcherAdapter () {
|
||||
new TextWatcherAdapter() {
|
||||
@Override
|
||||
public void afterTextChanged (@NonNull Editable s) {
|
||||
final var text = s.toString ().trim ();
|
||||
if (TextUtils.isEmpty (text)) {
|
||||
public void afterTextChanged(@NonNull Editable s) {
|
||||
final var text = s.toString().trim();
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
notifyValueChanged (text);
|
||||
|
||||
notifyValueChanged(text);
|
||||
}
|
||||
};
|
||||
|
||||
dimensionResInput.addTextChangedListener (dimensionResInputWatcher);
|
||||
|
||||
|
||||
dimensionResInput.addTextChangedListener(dimensionResInputWatcher);
|
||||
|
||||
final var future =
|
||||
CompletableFuture.supplyAsync (
|
||||
CompletableFuture.supplyAsync(
|
||||
() -> {
|
||||
final var list = new ArrayList<String> ();
|
||||
final var tables = ValuesTableFactory.getAllTables ();
|
||||
for (var entry : tables.entrySet ()) {
|
||||
final var dimens = entry.getValue ().getTable ("dimen");
|
||||
final var list = new ArrayList<String>();
|
||||
final var tables = ValuesTableFactory.getAllTables();
|
||||
for (var entry : tables.entrySet()) {
|
||||
final var dimens = entry.getValue().getTable("dimen");
|
||||
if (dimens != null) {
|
||||
list.addAll (
|
||||
dimens.keySet ().stream ()
|
||||
.map ("@dimen/"::concat)
|
||||
.collect (Collectors.toSet ()));
|
||||
list.addAll(
|
||||
dimens.keySet().stream()
|
||||
.map("@dimen/"::concat)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
}
|
||||
|
||||
list.addAll (FrameworkValues.listDimens ()
|
||||
.stream ()
|
||||
.map ("@android:dimen/"::concat)
|
||||
.collect (Collectors.toList ())
|
||||
);
|
||||
|
||||
list.addAll(
|
||||
FrameworkValues.listDimens().stream()
|
||||
.map("@android:dimen/"::concat)
|
||||
.collect(Collectors.toList()));
|
||||
return list;
|
||||
});
|
||||
future.whenComplete (
|
||||
future.whenComplete(
|
||||
(list, throwable) -> {
|
||||
if (list == null || list.isEmpty ()) {
|
||||
LOG.error ("No completion items found");
|
||||
if (list == null || list.isEmpty()) {
|
||||
LOG.error("No completion items found");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug ("Found", list.size (), "dimension resources for completion");
|
||||
|
||||
ThreadUtils.runOnUiThread (
|
||||
|
||||
LOG.debug("Found", list.size(), "dimension resources for completion");
|
||||
|
||||
ThreadUtils.runOnUiThread(
|
||||
() -> {
|
||||
final var adapter =
|
||||
new AttrValueCompletionAdapter (requireContext (), list);
|
||||
dimensionResInput.setThreshold (1);
|
||||
dimensionResInput.setAdapter (adapter);
|
||||
adapter.notifyDataSetChanged ();
|
||||
new AttrValueCompletionAdapter(requireContext(), list);
|
||||
dimensionResInput.setThreshold(1);
|
||||
dimensionResInput.setAdapter(adapter);
|
||||
adapter.notifyDataSetChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private String[] getDimensionUnits () {
|
||||
private String[] getDimensionUnits() {
|
||||
if (dimensionUnits == null) {
|
||||
dimensionUnits =
|
||||
requireContext ().getResources ().getStringArray (R.array.dimension_units);
|
||||
requireContext().getResources().getStringArray(R.array.dimension_units);
|
||||
}
|
||||
|
||||
|
||||
return dimensionUnits;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void notifyValueChanged (@NonNull String newValue) {
|
||||
protected void notifyValueChanged(@NonNull String newValue) {
|
||||
try {
|
||||
super.notifyValueChanged (newValue);
|
||||
super.notifyValueChanged(newValue);
|
||||
} catch (Throwable e) {
|
||||
LOG.error ("Unable to update dimension value to '" + newValue + "'", e);
|
||||
LOG.error("Unable to update dimension value to '" + newValue + "'", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,223 +42,223 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BuildServiceHandler extends IDEHandler implements BuildListener {
|
||||
|
||||
|
||||
private IDEService service;
|
||||
private boolean shouldInstallApk = false;
|
||||
|
||||
public BuildServiceHandler (Provider provider) {
|
||||
super (provider);
|
||||
|
||||
public BuildServiceHandler(Provider provider) {
|
||||
super(provider);
|
||||
}
|
||||
|
||||
public IDEService getService () {
|
||||
|
||||
public IDEService getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start () {
|
||||
Objects.requireNonNull (this.activity ());
|
||||
|
||||
AndroidProject project = provider.provideAndroidProject ();
|
||||
Objects.requireNonNull (project);
|
||||
Objects.requireNonNull (project.getProjectPath ());
|
||||
|
||||
this.service = new IDEService (new File (project.getProjectPath ()));
|
||||
this.service.setListener (this);
|
||||
public void start() {
|
||||
Objects.requireNonNull(this.activity());
|
||||
|
||||
AndroidProject project = provider.provideAndroidProject();
|
||||
Objects.requireNonNull(project);
|
||||
Objects.requireNonNull(project.getProjectPath());
|
||||
|
||||
this.service = new IDEService(new File(project.getProjectPath()));
|
||||
this.service.setListener(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stop () {
|
||||
this.service.stopAllDaemons ();
|
||||
this.service.exit ();
|
||||
public void stop() {
|
||||
this.service.stopAllDaemons();
|
||||
this.service.exit();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBuildModified () {
|
||||
public void onBuildModified() {
|
||||
// Does nothing currently
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onProjectLoaded (IDEProject project, Optional<IDEModule> appModule) {
|
||||
project.iconPath = provider.provideAndroidProject ().getIconPath ();
|
||||
activity ().setIDEProject (project);
|
||||
|
||||
if (appModule.isPresent ()) {
|
||||
IDEModule app = appModule.get ();
|
||||
activity ().setStatus (activity ().getString (R.string.msg_starting_completion));
|
||||
|
||||
public void onProjectLoaded(IDEProject project, Optional<IDEModule> appModule) {
|
||||
project.iconPath = provider.provideAndroidProject().getIconPath();
|
||||
activity().setIDEProject(project);
|
||||
|
||||
if (appModule.isPresent()) {
|
||||
IDEModule app = appModule.get();
|
||||
activity().setStatus(activity().getString(R.string.msg_starting_completion));
|
||||
|
||||
final List<String> paths =
|
||||
app.dependencies.stream ()
|
||||
.filter (this::isClasspathValid)
|
||||
.collect (Collectors.toList ());
|
||||
|
||||
provider.provideAndroidProject ().setClassPaths (paths);
|
||||
|
||||
app.dependencies.stream()
|
||||
.filter(this::isClasspathValid)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
provider.provideAndroidProject().setClassPaths(paths);
|
||||
|
||||
File androidJar =
|
||||
new File (
|
||||
new File(
|
||||
Environment.ANDROID_HOME,
|
||||
String.format ("platforms/%s/android.jar", app.compileSdkVersion));
|
||||
if (androidJar.exists ()) {
|
||||
Environment.setBootClasspath (androidJar);
|
||||
provider.provideAndroidProject ().addClasspath (androidJar.getAbsolutePath ());
|
||||
activity ().updateServices ();
|
||||
String.format("platforms/%s/android.jar", app.compileSdkVersion));
|
||||
if (androidJar.exists()) {
|
||||
Environment.setBootClasspath(androidJar);
|
||||
provider.provideAndroidProject().addClasspath(androidJar.getAbsolutePath());
|
||||
activity().updateServices();
|
||||
} else {
|
||||
activity ().setStatus ("android.jar not found!");
|
||||
activity().setStatus("android.jar not found!");
|
||||
}
|
||||
} else {
|
||||
activity ().setStatus ("Cannot get :app module...");
|
||||
activity().setStatus("Cannot get :app module...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartingGradleDaemon (GradleTask task) {
|
||||
activity ().setStatus (activity ().getString (R.string.msg_starting_daemon));
|
||||
public void onStartingGradleDaemon(GradleTask task) {
|
||||
activity().setStatus(activity().getString(R.string.msg_starting_daemon));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRunTask (GradleTask task, String name) {
|
||||
if (task != null && task.canOutput ()) {
|
||||
activity ().setStatus (service.typeString (task.getTaskID ()) + " " + name);
|
||||
public void onRunTask(GradleTask task, String name) {
|
||||
if (task != null && task.canOutput()) {
|
||||
activity().setStatus(service.typeString(task.getTaskID()) + " " + name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBuildSuccessful (GradleTask task, String msg) {
|
||||
appendOutput (task, msg);
|
||||
if (task == null || activity () == null) {
|
||||
public void onBuildSuccessful(GradleTask task, String msg) {
|
||||
appendOutput(task, msg);
|
||||
if (task == null || activity() == null) {
|
||||
return;
|
||||
}
|
||||
if (task.canOutput ()) {
|
||||
activity ().setStatus (msg);
|
||||
if (task.canOutput()) {
|
||||
activity().setStatus(msg);
|
||||
}
|
||||
|
||||
|
||||
// If this task generates APK, ask user if he/she wants to install them
|
||||
if (shouldInstallApk && task instanceof ApkGeneratingTask) {
|
||||
final IDEProject project = activity ().provideIDEProject ();
|
||||
final IDEProject project = activity().provideIDEProject();
|
||||
final Optional<IDEModule> app =
|
||||
project.getModuleByPath (":app"); // TODO Handle multiple application modules
|
||||
if (app.isPresent ()) {
|
||||
final String path = app.get ().projectDir;
|
||||
project.getModuleByPath(":app"); // TODO Handle multiple application modules
|
||||
if (app.isPresent()) {
|
||||
final String path = app.get().projectDir;
|
||||
if (path != null) {
|
||||
final File buildDir = new File (path, "build");
|
||||
installApks (((ApkGeneratingTask) task).getApks (buildDir));
|
||||
final File buildDir = new File(path, "build");
|
||||
installApks(((ApkGeneratingTask) task).getApks(buildDir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activity ()
|
||||
.getApp ()
|
||||
.getPrefManager ()
|
||||
.putBoolean (PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false);
|
||||
activity ().invalidateOptionsMenu ();
|
||||
activity ().getBinding ().buildProgressIndicator.setVisibility (View.GONE);
|
||||
|
||||
activity()
|
||||
.getApp()
|
||||
.getPrefManager()
|
||||
.putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false);
|
||||
activity().invalidateOptionsMenu();
|
||||
activity().getBinding().buildProgressIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBuildFailed (GradleTask task, String msg) {
|
||||
appendOutput (task, msg);
|
||||
public void onBuildFailed(GradleTask task, String msg) {
|
||||
appendOutput(task, msg);
|
||||
if (task == null) {
|
||||
return;
|
||||
}
|
||||
if (task.canOutput ()) {
|
||||
activity ().setStatus (msg);
|
||||
if (task.canOutput()) {
|
||||
activity().setStatus(msg);
|
||||
}
|
||||
|
||||
activity ()
|
||||
.getApp ()
|
||||
.getPrefManager ()
|
||||
.putBoolean (PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false);
|
||||
activity ().invalidateOptionsMenu ();
|
||||
activity ().getBinding ().buildProgressIndicator.setVisibility (View.GONE);
|
||||
|
||||
activity()
|
||||
.getApp()
|
||||
.getPrefManager()
|
||||
.putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false);
|
||||
activity().invalidateOptionsMenu();
|
||||
activity().getBinding().buildProgressIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void saveFiles () {
|
||||
activity ().saveAll (false, false);
|
||||
public void saveFiles() {
|
||||
activity().saveAll(false, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void appendOutput (GradleTask task, CharSequence text) {
|
||||
public void appendOutput(GradleTask task, CharSequence text) {
|
||||
if (text == null) {
|
||||
return;
|
||||
}
|
||||
if (task != null && !task.canOutput ()) {
|
||||
if (task != null && !task.canOutput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
activity ().appendBuildOut (text.toString ());
|
||||
|
||||
activity().appendBuildOut(text.toString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void prepareBuild () {
|
||||
public void prepareBuild() {
|
||||
boolean isFirstBuild =
|
||||
activity ()
|
||||
.getApp ()
|
||||
.getPrefManager ()
|
||||
.getBoolean (PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true);
|
||||
activity ()
|
||||
.setStatus (
|
||||
activity ()
|
||||
.getString (
|
||||
activity()
|
||||
.getApp()
|
||||
.getPrefManager()
|
||||
.getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true);
|
||||
activity()
|
||||
.setStatus(
|
||||
activity()
|
||||
.getString(
|
||||
isFirstBuild
|
||||
? R.string.preparing_first
|
||||
: R.string.preparing));
|
||||
if (isFirstBuild) {
|
||||
activity ().showFirstBuildNotice ();
|
||||
activity().showFirstBuildNotice();
|
||||
}
|
||||
activity ().getBinding ().buildProgressIndicator.setVisibility (View.VISIBLE);
|
||||
activity().getBinding().buildProgressIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void setShouldInstallApk (boolean install) {
|
||||
|
||||
public void setShouldInstallApk(boolean install) {
|
||||
this.shouldInstallApk = install;
|
||||
}
|
||||
|
||||
public void assembleDebug (boolean shouldInstallApk) {
|
||||
setShouldInstallApk (shouldInstallApk);
|
||||
getService ().assembleDebug (shouldInstallApk);
|
||||
|
||||
public void assembleDebug(boolean shouldInstallApk) {
|
||||
setShouldInstallApk(shouldInstallApk);
|
||||
getService().assembleDebug(shouldInstallApk);
|
||||
}
|
||||
|
||||
private boolean isClasspathValid (String path) {
|
||||
if (path == null || path.trim ().length () <= 0 || path.trim ().equals ("/")) {
|
||||
|
||||
private boolean isClasspathValid(String path) {
|
||||
if (path == null || path.trim().length() <= 0 || path.trim().equals("/")) {
|
||||
return false;
|
||||
}
|
||||
File file = new File (path);
|
||||
return file.isFile ()
|
||||
&& file.getName ().endsWith (".jar")
|
||||
File file = new File(path);
|
||||
return file.isFile()
|
||||
&& file.getName().endsWith(".jar")
|
||||
// Release R.jar shouldn't be included in classpath
|
||||
&& !file.getAbsolutePath ().endsWith ("/release/R.jar");
|
||||
&& !file.getAbsolutePath().endsWith("/release/R.jar");
|
||||
}
|
||||
|
||||
private void installApks (final Set<File> apks) {
|
||||
if (activity () == null || apks == null || apks.isEmpty ()) {
|
||||
|
||||
private void installApks(final Set<File> apks) {
|
||||
if (activity() == null || apks == null || apks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apks.size () == 1) {
|
||||
activity ().install (apks.iterator ().next ());
|
||||
|
||||
if (apks.size() == 1) {
|
||||
activity().install(apks.iterator().next());
|
||||
} else {
|
||||
final List<File> files = new ArrayList<> (apks);
|
||||
final List<File> files = new ArrayList<>(apks);
|
||||
final MaterialAlertDialogBuilder builder =
|
||||
DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
builder.setTitle (activity ().getString (R.string.title_install_apks));
|
||||
builder.setItems (
|
||||
getNames (files),
|
||||
DialogUtils.newMaterialDialogBuilder(activity());
|
||||
builder.setTitle(activity().getString(R.string.title_install_apks));
|
||||
builder.setItems(
|
||||
getNames(files),
|
||||
(d, w) -> {
|
||||
d.dismiss ();
|
||||
activity ().install (files.get (w));
|
||||
d.dismiss();
|
||||
activity().install(files.get(w));
|
||||
});
|
||||
builder.show ();
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence[] getNames (final Collection<File> apks) {
|
||||
final String[] names = new String[apks.size ()];
|
||||
|
||||
|
||||
private CharSequence[] getNames(final Collection<File> apks) {
|
||||
final String[] names = new String[apks.size()];
|
||||
|
||||
int i = 0;
|
||||
for (File apk : apks) {
|
||||
names[i] = apk.getName ();
|
||||
names[i] = apk.getName();
|
||||
++i;
|
||||
}
|
||||
|
||||
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,403 +41,402 @@ import java.util.regex.Pattern;
|
||||
|
||||
public class FileOptionsHandler extends IDEHandler
|
||||
implements OptionsListFragment.OnOptionsClickListener {
|
||||
|
||||
|
||||
public static final String RES_PATH_REGEX = "/.*/src/.*/res";
|
||||
public static final String LAYOUT_RES_PATH_REGEX = "/.*/src/.*/res/layout";
|
||||
public static final String MENU_RES_PATH_REGEX = "/.*/src/.*/res/menu";
|
||||
public static final String DRAWABLE_RES_PATH_REGEX = "/.*/src/.*/res/drawable";
|
||||
public static final String JAVA_PATH_REGEX = "/.*/src/.*/java";
|
||||
|
||||
public FileOptionsHandler (Provider provider) {
|
||||
super (provider);
|
||||
|
||||
public FileOptionsHandler(Provider provider) {
|
||||
super(provider);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start () {
|
||||
Objects.requireNonNull (this.activity ());
|
||||
public void start() {
|
||||
Objects.requireNonNull(this.activity());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stop () {
|
||||
}
|
||||
|
||||
public void stop() {}
|
||||
|
||||
@Override
|
||||
public void onOptionsClick (SheetOption option) {
|
||||
public void onOptionsClick(SheetOption option) {
|
||||
if (option.extra instanceof File) {
|
||||
final File f = (File) option.extra;
|
||||
switch (option.id) {
|
||||
case 0:
|
||||
ClipboardUtils.copyText ("[AndroidIDE] Copied File Path", f.getAbsolutePath ());
|
||||
activity ().getApp ().toast (R.string.copied, Toaster.Type.SUCCESS);
|
||||
ClipboardUtils.copyText("[AndroidIDE] Copied File Path", f.getAbsolutePath());
|
||||
activity().getApp().toast(R.string.copied, Toaster.Type.SUCCESS);
|
||||
break;
|
||||
case 1:
|
||||
renameFile (f);
|
||||
renameFile(f);
|
||||
break;
|
||||
case 2:
|
||||
delete (f);
|
||||
delete(f);
|
||||
break;
|
||||
case 3:
|
||||
createNewFile (f);
|
||||
createNewFile(f);
|
||||
break;
|
||||
case 4:
|
||||
createNewFolder (f);
|
||||
createNewFolder(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createNewFile (File f) {
|
||||
createNewFile (f, false);
|
||||
|
||||
private void createNewFile(File f) {
|
||||
createNewFile(f, false);
|
||||
}
|
||||
|
||||
private void createNewFile (final File f, boolean forceUnknownType) {
|
||||
|
||||
private void createNewFile(final File f, boolean forceUnknownType) {
|
||||
if (forceUnknownType) {
|
||||
createNewEmptyFile (f);
|
||||
createNewEmptyFile(f);
|
||||
} else {
|
||||
final boolean isJava =
|
||||
Pattern.compile (
|
||||
Pattern.quote (androidProject ().getProjectPath ())
|
||||
+ JAVA_PATH_REGEX)
|
||||
.matcher (f.getAbsolutePath ())
|
||||
.find ();
|
||||
Pattern.compile(
|
||||
Pattern.quote(androidProject().getProjectPath())
|
||||
+ JAVA_PATH_REGEX)
|
||||
.matcher(f.getAbsolutePath())
|
||||
.find();
|
||||
final boolean isRes =
|
||||
Pattern.compile (
|
||||
Pattern.quote (androidProject ().getProjectPath ())
|
||||
+ RES_PATH_REGEX)
|
||||
.matcher (f.getAbsolutePath ())
|
||||
.find ();
|
||||
Pattern.compile(
|
||||
Pattern.quote(androidProject().getProjectPath())
|
||||
+ RES_PATH_REGEX)
|
||||
.matcher(f.getAbsolutePath())
|
||||
.find();
|
||||
final boolean isLayoutRes =
|
||||
Pattern.compile (
|
||||
Pattern.quote (androidProject ().getProjectPath ())
|
||||
+ LAYOUT_RES_PATH_REGEX)
|
||||
.matcher (f.getAbsolutePath ())
|
||||
.find ();
|
||||
Pattern.compile(
|
||||
Pattern.quote(androidProject().getProjectPath())
|
||||
+ LAYOUT_RES_PATH_REGEX)
|
||||
.matcher(f.getAbsolutePath())
|
||||
.find();
|
||||
final boolean isMenuRes =
|
||||
Pattern.compile (
|
||||
Pattern.quote (androidProject ().getProjectPath ())
|
||||
+ MENU_RES_PATH_REGEX)
|
||||
.matcher (f.getAbsolutePath ())
|
||||
.find ();
|
||||
Pattern.compile(
|
||||
Pattern.quote(androidProject().getProjectPath())
|
||||
+ MENU_RES_PATH_REGEX)
|
||||
.matcher(f.getAbsolutePath())
|
||||
.find();
|
||||
final boolean isDrawableRes =
|
||||
Pattern.compile (
|
||||
Pattern.quote (androidProject ().getProjectPath ())
|
||||
+ DRAWABLE_RES_PATH_REGEX)
|
||||
.matcher (f.getAbsolutePath ())
|
||||
.find ();
|
||||
Pattern.compile(
|
||||
Pattern.quote(androidProject().getProjectPath())
|
||||
+ DRAWABLE_RES_PATH_REGEX)
|
||||
.matcher(f.getAbsolutePath())
|
||||
.find();
|
||||
if (isJava) {
|
||||
createJavaClass (f);
|
||||
} else if (isLayoutRes && f.getName ().equals ("layout")) {
|
||||
createLayoutRes (f);
|
||||
} else if (isMenuRes && f.getName ().equals ("menu")) {
|
||||
createMenuRes (f);
|
||||
} else if (isDrawableRes && f.getName ().equals ("drawable")) {
|
||||
createDrawableRes (f);
|
||||
} else if (isRes && f.getName ().equals ("res")) {
|
||||
createNewResource (f);
|
||||
createJavaClass(f);
|
||||
} else if (isLayoutRes && f.getName().equals("layout")) {
|
||||
createLayoutRes(f);
|
||||
} else if (isMenuRes && f.getName().equals("menu")) {
|
||||
createMenuRes(f);
|
||||
} else if (isDrawableRes && f.getName().equals("drawable")) {
|
||||
createDrawableRes(f);
|
||||
} else if (isRes && f.getName().equals("res")) {
|
||||
createNewResource(f);
|
||||
} else {
|
||||
createNewEmptyFile (f);
|
||||
createNewEmptyFile(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createJavaClass (final File f) {
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
|
||||
private void createJavaClass(final File f) {
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||
final LayoutCreateFileJavaBinding binding =
|
||||
LayoutCreateFileJavaBinding.inflate (activity ().getLayoutInflater ());
|
||||
builder.setView (binding.getRoot ());
|
||||
builder.setTitle (R.string.new_java_class);
|
||||
builder.setPositiveButton (
|
||||
LayoutCreateFileJavaBinding.inflate(activity().getLayoutInflater());
|
||||
builder.setView(binding.getRoot());
|
||||
builder.setTitle(R.string.new_java_class);
|
||||
builder.setPositiveButton(
|
||||
R.string.text_create,
|
||||
(p1, p2) -> {
|
||||
p1.dismiss ();
|
||||
p1.dismiss();
|
||||
final String name =
|
||||
Objects.requireNonNull (binding.name.getEditText ())
|
||||
.getText ()
|
||||
.toString ()
|
||||
.trim ();
|
||||
final String pkgName = ProjectWriter.getPackageName (f);
|
||||
if (pkgName == null || pkgName.trim ().length () <= 0) {
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (R.string.msg_get_package_failed, Toaster.Type.ERROR);
|
||||
Objects.requireNonNull(binding.name.getEditText())
|
||||
.getText()
|
||||
.toString()
|
||||
.trim();
|
||||
final String pkgName = ProjectWriter.getPackageName(f);
|
||||
if (pkgName == null || pkgName.trim().length() <= 0) {
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(R.string.msg_get_package_failed, Toaster.Type.ERROR);
|
||||
} else {
|
||||
final int id = binding.typeGroup.getCheckedButtonId ();
|
||||
final var javaName = name.endsWith (".java") ? name : name.concat (".java");
|
||||
final int id = binding.typeGroup.getCheckedButtonId();
|
||||
final var javaName = name.endsWith(".java") ? name : name.concat(".java");
|
||||
final var className =
|
||||
!name.contains (".")
|
||||
!name.contains(".")
|
||||
? name
|
||||
: name.substring (0, name.lastIndexOf ("."));
|
||||
if (id == binding.typeClass.getId ()) {
|
||||
createFile (
|
||||
f, javaName, ProjectWriter.createJavaClass (pkgName, className));
|
||||
} else if (id == binding.typeInterface.getId ()) {
|
||||
createFile (
|
||||
: name.substring(0, name.lastIndexOf("."));
|
||||
if (id == binding.typeClass.getId()) {
|
||||
createFile(
|
||||
f, javaName, ProjectWriter.createJavaClass(pkgName, className));
|
||||
} else if (id == binding.typeInterface.getId()) {
|
||||
createFile(
|
||||
f,
|
||||
javaName,
|
||||
ProjectWriter.createJavaInterface (pkgName, className));
|
||||
} else if (id == binding.typeEnum.getId ()) {
|
||||
createFile (
|
||||
f, javaName, ProjectWriter.createJavaEnum (pkgName, className));
|
||||
} else if (id == binding.typeActivity.getId ()) {
|
||||
createFile (
|
||||
f, javaName, ProjectWriter.createActivity (pkgName, className));
|
||||
ProjectWriter.createJavaInterface(pkgName, className));
|
||||
} else if (id == binding.typeEnum.getId()) {
|
||||
createFile(
|
||||
f, javaName, ProjectWriter.createJavaEnum(pkgName, className));
|
||||
} else if (id == binding.typeActivity.getId()) {
|
||||
createFile(
|
||||
f, javaName, ProjectWriter.createActivity(pkgName, className));
|
||||
} else {
|
||||
createFile (f, name, "");
|
||||
createFile(f, name, "");
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton (android.R.string.cancel, null);
|
||||
builder.setCancelable (false);
|
||||
builder.create ().show ();
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.setCancelable(false);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void createLayoutRes (File f) {
|
||||
createNewFileWithContent (
|
||||
Environment.mkdirIfNotExits (f), ProjectWriter.createLayout (), ".xml");
|
||||
|
||||
private void createLayoutRes(File f) {
|
||||
createNewFileWithContent(
|
||||
Environment.mkdirIfNotExits(f), ProjectWriter.createLayout(), ".xml");
|
||||
}
|
||||
|
||||
private void createMenuRes (File f) {
|
||||
createNewFileWithContent (
|
||||
Environment.mkdirIfNotExits (f), ProjectWriter.createMenu (), ".xml");
|
||||
|
||||
private void createMenuRes(File f) {
|
||||
createNewFileWithContent(
|
||||
Environment.mkdirIfNotExits(f), ProjectWriter.createMenu(), ".xml");
|
||||
}
|
||||
|
||||
private void createDrawableRes (File f) {
|
||||
createNewFileWithContent (
|
||||
Environment.mkdirIfNotExits (f), ProjectWriter.createDrawable (), ".xml");
|
||||
|
||||
private void createDrawableRes(File f) {
|
||||
createNewFileWithContent(
|
||||
Environment.mkdirIfNotExits(f), ProjectWriter.createDrawable(), ".xml");
|
||||
}
|
||||
|
||||
private void createNewResource (File f) {
|
||||
|
||||
private void createNewResource(File f) {
|
||||
final String[] labels = {
|
||||
activity ().getString (R.string.restype_drawable),
|
||||
activity ().getString (R.string.restype_layout),
|
||||
activity ().getString (R.string.restype_menu),
|
||||
activity ().getString (R.string.restype_other)
|
||||
activity().getString(R.string.restype_drawable),
|
||||
activity().getString(R.string.restype_layout),
|
||||
activity().getString(R.string.restype_menu),
|
||||
activity().getString(R.string.restype_other)
|
||||
};
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
builder.setTitle (R.string.new_xml_resource);
|
||||
builder.setItems (
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||
builder.setTitle(R.string.new_xml_resource);
|
||||
builder.setItems(
|
||||
labels,
|
||||
(dialogInterface, position) -> {
|
||||
if (position == 0) {
|
||||
createDrawableRes (new File (f, "drawable"));
|
||||
createDrawableRes(new File(f, "drawable"));
|
||||
} else if (position == 1) {
|
||||
createLayoutRes (new File (f, "layout"));
|
||||
createLayoutRes(new File(f, "layout"));
|
||||
} else if (position == 2) {
|
||||
createMenuRes (new File (f, "menu"));
|
||||
createMenuRes(new File(f, "menu"));
|
||||
} else if (position == 3) {
|
||||
createNewFile (f, true);
|
||||
createNewFile(f, true);
|
||||
}
|
||||
});
|
||||
builder.create ().show ();
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void createNewEmptyFile (File f) {
|
||||
createNewFileWithContent (f, "");
|
||||
|
||||
private void createNewEmptyFile(File f) {
|
||||
createNewFileWithContent(f, "");
|
||||
}
|
||||
|
||||
private void createNewFileWithContent (File f, String content) {
|
||||
createNewFileWithContent (f, content, null);
|
||||
|
||||
private void createNewFileWithContent(File f, String content) {
|
||||
createNewFileWithContent(f, content, null);
|
||||
}
|
||||
|
||||
private void createNewFileWithContent (File folder, String content, String extension) {
|
||||
|
||||
private void createNewFileWithContent(File folder, String content, String extension) {
|
||||
final LayoutDialogTextInputBinding binding =
|
||||
LayoutDialogTextInputBinding.inflate (activity ().getLayoutInflater ());
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
|
||||
Objects.requireNonNull (binding.name.getEditText ()).setHint (R.string.file_name);
|
||||
|
||||
builder.setTitle (R.string.new_file);
|
||||
builder.setMessage (
|
||||
activity ()
|
||||
.getString (R.string.msg_can_contain_slashes)
|
||||
.concat ("\n\n")
|
||||
.concat (
|
||||
activity ()
|
||||
.getString (
|
||||
LayoutDialogTextInputBinding.inflate(activity().getLayoutInflater());
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||
|
||||
Objects.requireNonNull(binding.name.getEditText()).setHint(R.string.file_name);
|
||||
|
||||
builder.setTitle(R.string.new_file);
|
||||
builder.setMessage(
|
||||
activity()
|
||||
.getString(R.string.msg_can_contain_slashes)
|
||||
.concat("\n\n")
|
||||
.concat(
|
||||
activity()
|
||||
.getString(
|
||||
R.string.msg_newfile_dest,
|
||||
folder.getAbsolutePath ())));
|
||||
builder.setView (binding.getRoot ());
|
||||
builder.setCancelable (false);
|
||||
builder.setPositiveButton (
|
||||
folder.getAbsolutePath())));
|
||||
builder.setView(binding.getRoot());
|
||||
builder.setCancelable(false);
|
||||
builder.setPositiveButton(
|
||||
R.string.text_create,
|
||||
(p1, p2) -> {
|
||||
p1.dismiss ();
|
||||
String name = binding.name.getEditText ().getText ().toString ().trim ();
|
||||
if (extension != null && extension.trim ().length () > 0) {
|
||||
name = name.endsWith (extension) ? name : name.concat (extension);
|
||||
p1.dismiss();
|
||||
String name = binding.name.getEditText().getText().toString().trim();
|
||||
if (extension != null && extension.trim().length() > 0) {
|
||||
name = name.endsWith(extension) ? name : name.concat(extension);
|
||||
}
|
||||
createFile (folder, name, content);
|
||||
createFile(folder, name, content);
|
||||
});
|
||||
builder.setNegativeButton (android.R.string.cancel, null);
|
||||
builder.create ().show ();
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void createFile (File f, String name, String content) {
|
||||
if (name.length () > 0 && name.length () <= 40 && !name.startsWith ("/")) {
|
||||
final File file = new File (f, name);
|
||||
if (file.exists ()) {
|
||||
activity ().getApp ().toast (R.string.msg_file_exists, Toaster.Type.ERROR);
|
||||
|
||||
private void createFile(File f, String name, String content) {
|
||||
if (name.length() > 0 && name.length() <= 40 && !name.startsWith("/")) {
|
||||
final File file = new File(f, name);
|
||||
if (file.exists()) {
|
||||
activity().getApp().toast(R.string.msg_file_exists, Toaster.Type.ERROR);
|
||||
} else {
|
||||
if (FileIOUtils.writeFileFromString (file, content)) {
|
||||
if (FileIOUtils.writeFileFromString(file, content)) {
|
||||
// TODO Notify language servers about file created event
|
||||
activity ().getApp ().toast (R.string.msg_file_created, Toaster.Type.SUCCESS);
|
||||
if (activity ().getLastHoldTreeNode () != null) {
|
||||
TreeNode node = new TreeNode (file);
|
||||
node.setViewHolder (new FileTreeViewHolder (activity ()));
|
||||
activity ().getLastHoldTreeNode ().addChild (node);
|
||||
activity ()
|
||||
.getFileTreeFragment ()
|
||||
.expandNode (activity ().getLastHoldTreeNode ());
|
||||
activity().getApp().toast(R.string.msg_file_created, Toaster.Type.SUCCESS);
|
||||
if (activity().getLastHoldTreeNode() != null) {
|
||||
TreeNode node = new TreeNode(file);
|
||||
node.setViewHolder(new FileTreeViewHolder(activity()));
|
||||
activity().getLastHoldTreeNode().addChild(node);
|
||||
activity()
|
||||
.getFileTreeFragment()
|
||||
.expandNode(activity().getLastHoldTreeNode());
|
||||
} else {
|
||||
activity ().getFileTreeFragment ().listProjectFiles ();
|
||||
activity().getFileTreeFragment().listProjectFiles();
|
||||
}
|
||||
} else {
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (R.string.msg_file_creation_failed, Toaster.Type.ERROR);
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(R.string.msg_file_creation_failed, Toaster.Type.ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activity ().getApp ().toast (R.string.msg_invalid_name, Toaster.Type.ERROR);
|
||||
activity().getApp().toast(R.string.msg_invalid_name, Toaster.Type.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void createNewFolder (File f) {
|
||||
|
||||
private void createNewFolder(File f) {
|
||||
final LayoutDialogTextInputBinding binding =
|
||||
LayoutDialogTextInputBinding.inflate (activity ().getLayoutInflater ());
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
|
||||
Objects.requireNonNull (binding.name.getEditText ()).setHint (R.string.folder_name);
|
||||
|
||||
builder.setTitle (R.string.new_folder);
|
||||
builder.setMessage (R.string.msg_can_contain_slashes);
|
||||
builder.setView (binding.getRoot ());
|
||||
builder.setCancelable (false);
|
||||
builder.setPositiveButton (
|
||||
LayoutDialogTextInputBinding.inflate(activity().getLayoutInflater());
|
||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||
|
||||
Objects.requireNonNull(binding.name.getEditText()).setHint(R.string.folder_name);
|
||||
|
||||
builder.setTitle(R.string.new_folder);
|
||||
builder.setMessage(R.string.msg_can_contain_slashes);
|
||||
builder.setView(binding.getRoot());
|
||||
builder.setCancelable(false);
|
||||
builder.setPositiveButton(
|
||||
R.string.text_create,
|
||||
(p1, p2) -> {
|
||||
p1.dismiss ();
|
||||
final String name = binding.name.getEditText ().getText ().toString ().trim ();
|
||||
if (name.length () > 0 && name.length () <= 40 && !name.startsWith ("/")) {
|
||||
final File file = new File (f, name);
|
||||
if (file.exists ()) {
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (R.string.msg_folder_exists, Toaster.Type.ERROR);
|
||||
p1.dismiss();
|
||||
final String name = binding.name.getEditText().getText().toString().trim();
|
||||
if (name.length() > 0 && name.length() <= 40 && !name.startsWith("/")) {
|
||||
final File file = new File(f, name);
|
||||
if (file.exists()) {
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(R.string.msg_folder_exists, Toaster.Type.ERROR);
|
||||
} else {
|
||||
if (file.mkdirs ()) {
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (R.string.msg_folder_created, Toaster.Type.SUCCESS);
|
||||
if (activity ().getLastHoldTreeNode () != null) {
|
||||
TreeNode node = new TreeNode (file);
|
||||
node.setViewHolder (new FileTreeViewHolder (activity ()));
|
||||
activity ().getLastHoldTreeNode ().addChild (node);
|
||||
activity ()
|
||||
.getFileTreeFragment ()
|
||||
.expandNode (activity ().getLastHoldTreeNode ());
|
||||
if (file.mkdirs()) {
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(R.string.msg_folder_created, Toaster.Type.SUCCESS);
|
||||
if (activity().getLastHoldTreeNode() != null) {
|
||||
TreeNode node = new TreeNode(file);
|
||||
node.setViewHolder(new FileTreeViewHolder(activity()));
|
||||
activity().getLastHoldTreeNode().addChild(node);
|
||||
activity()
|
||||
.getFileTreeFragment()
|
||||
.expandNode(activity().getLastHoldTreeNode());
|
||||
} else {
|
||||
activity ().getFileTreeFragment ().listProjectFiles ();
|
||||
activity().getFileTreeFragment().listProjectFiles();
|
||||
}
|
||||
} else {
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(
|
||||
R.string.msg_folder_creation_failed,
|
||||
Toaster.Type.ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activity ().getApp ().toast (R.string.msg_invalid_name, Toaster.Type.ERROR);
|
||||
activity().getApp().toast(R.string.msg_invalid_name, Toaster.Type.ERROR);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton (android.R.string.cancel, null);
|
||||
builder.create ().show ();
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void delete (final File f) {
|
||||
MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
builder.setNegativeButton (R.string.no, null)
|
||||
.setPositiveButton (
|
||||
|
||||
private void delete(final File f) {
|
||||
MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||
builder.setNegativeButton(R.string.no, null)
|
||||
.setPositiveButton(
|
||||
R.string.yes,
|
||||
(p1, p2) -> {
|
||||
p1.dismiss ();
|
||||
final boolean deleted = FileUtils.delete (f);
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (
|
||||
p1.dismiss();
|
||||
final boolean deleted = FileUtils.delete(f);
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(
|
||||
deleted ? R.string.deleted : R.string.delete_failed,
|
||||
deleted ? Toaster.Type.SUCCESS : Toaster.Type.ERROR);
|
||||
if (deleted) {
|
||||
// TODO Notify language servers about file delete event
|
||||
if (activity ().getLastHoldTreeNode () != null) {
|
||||
TreeNode parent = activity ().getLastHoldTreeNode ().getParent ();
|
||||
parent.deleteChild (activity ().getLastHoldTreeNode ());
|
||||
activity ().getFileTreeFragment ().expandNode (parent);
|
||||
if (activity().getLastHoldTreeNode() != null) {
|
||||
TreeNode parent = activity().getLastHoldTreeNode().getParent();
|
||||
parent.deleteChild(activity().getLastHoldTreeNode());
|
||||
activity().getFileTreeFragment().expandNode(parent);
|
||||
} else {
|
||||
activity ().getFileTreeFragment ().listProjectFiles ();
|
||||
activity().getFileTreeFragment().listProjectFiles();
|
||||
}
|
||||
|
||||
final var frag = activity ().getEditorForFile (f);
|
||||
|
||||
final var frag = activity().getEditorForFile(f);
|
||||
if (frag != null) {
|
||||
activity ()
|
||||
.closeFile (
|
||||
activity ()
|
||||
.findIndexOfEditorByFile (
|
||||
frag.getFile ()));
|
||||
activity()
|
||||
.closeFile(
|
||||
activity()
|
||||
.findIndexOfEditorByFile(
|
||||
frag.getFile()));
|
||||
}
|
||||
}
|
||||
})
|
||||
.setTitle (R.string.title_confirm_delete)
|
||||
.setMessage (
|
||||
activity ()
|
||||
.getString (
|
||||
.setTitle(R.string.title_confirm_delete)
|
||||
.setMessage(
|
||||
activity()
|
||||
.getString(
|
||||
R.string.msg_confirm_delete,
|
||||
String.format ("%s [%s]", f.getName (), f.getAbsolutePath ())))
|
||||
.setCancelable (false)
|
||||
.create ()
|
||||
.show ();
|
||||
String.format("%s [%s]", f.getName(), f.getAbsolutePath())))
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
private void renameFile (File f) {
|
||||
|
||||
private void renameFile(File f) {
|
||||
final LayoutDialogTextInputBinding binding =
|
||||
LayoutDialogTextInputBinding.inflate (LayoutInflater.from (activity ()));
|
||||
MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (activity ());
|
||||
|
||||
Objects.requireNonNull (binding.name.getEditText ())
|
||||
.setHint (activity ().getString (R.string.new_name));
|
||||
binding.name.getEditText ().setText (f.getName ());
|
||||
|
||||
builder.setTitle (R.string.rename_file);
|
||||
builder.setMessage (R.string.msg_rename_file);
|
||||
builder.setView (binding.getRoot ());
|
||||
builder.setNegativeButton (android.R.string.cancel, null);
|
||||
builder.setPositiveButton (
|
||||
LayoutDialogTextInputBinding.inflate(LayoutInflater.from(activity()));
|
||||
MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||
|
||||
Objects.requireNonNull(binding.name.getEditText())
|
||||
.setHint(activity().getString(R.string.new_name));
|
||||
binding.name.getEditText().setText(f.getName());
|
||||
|
||||
builder.setTitle(R.string.rename_file);
|
||||
builder.setMessage(R.string.msg_rename_file);
|
||||
builder.setView(binding.getRoot());
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.setPositiveButton(
|
||||
R.string.rename_file,
|
||||
(p1, p2) -> {
|
||||
p1.dismiss ();
|
||||
String name = binding.name.getEditText ().getText ().toString ().trim ();
|
||||
p1.dismiss();
|
||||
String name = binding.name.getEditText().getText().toString().trim();
|
||||
boolean renamed =
|
||||
name.length () > 0 && name.length () <= 40 && FileUtils.rename (f, name);
|
||||
activity ()
|
||||
.getApp ()
|
||||
.toast (
|
||||
name.length() > 0 && name.length() <= 40 && FileUtils.rename(f, name);
|
||||
activity()
|
||||
.getApp()
|
||||
.toast(
|
||||
renamed ? R.string.renamed : R.string.rename_failed,
|
||||
renamed ? Toaster.Type.SUCCESS : Toaster.Type.ERROR);
|
||||
if (renamed) {
|
||||
// TODO Notify language servers about file rename event
|
||||
if (activity ().getLastHoldTreeNode () != null) {
|
||||
TreeNode parent = activity ().getLastHoldTreeNode ().getParent ();
|
||||
parent.deleteChild (activity ().getLastHoldTreeNode ());
|
||||
TreeNode node = new TreeNode (new File (f.getParentFile (), name));
|
||||
node.setViewHolder (new FileTreeViewHolder (activity ()));
|
||||
parent.addChild (node);
|
||||
activity ().getFileTreeFragment ().expandNode (parent);
|
||||
if (activity().getLastHoldTreeNode() != null) {
|
||||
TreeNode parent = activity().getLastHoldTreeNode().getParent();
|
||||
parent.deleteChild(activity().getLastHoldTreeNode());
|
||||
TreeNode node = new TreeNode(new File(f.getParentFile(), name));
|
||||
node.setViewHolder(new FileTreeViewHolder(activity()));
|
||||
parent.addChild(node);
|
||||
activity().getFileTreeFragment().expandNode(parent);
|
||||
} else {
|
||||
activity ().getFileTreeFragment ().listProjectFiles ();
|
||||
activity().getFileTreeFragment().listProjectFiles();
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.create ().show ();
|
||||
builder.create().show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,16 +35,16 @@ import java.util.Properties;
|
||||
|
||||
@SuppressLint("SdCardPath")
|
||||
public final class Environment {
|
||||
|
||||
public static final Map<String, String> IDE_PROPS = new HashMap<> ();
|
||||
public static final Map<String, String> ENV_VARS = new HashMap<> ();
|
||||
|
||||
public static final Map<String, String> IDE_PROPS = new HashMap<>();
|
||||
public static final Map<String, String> ENV_VARS = new HashMap<>();
|
||||
public static final String PROJECTS_FOLDER = "AndroidIDEProjects";
|
||||
private static final String DEFAULT_JAVA_HOME =
|
||||
"/data/data/com.itsaky.androidide/files/framework/jdk";
|
||||
private static final String DEFAULT_ANDROID_HOME =
|
||||
"/data/data/com.itsaky.androidide/files/framework/android-sdk";
|
||||
private static final Logger LOG = Logger.instance ("Environment");
|
||||
private static final List<String> blacklist = new ArrayList<> ();
|
||||
private static final Logger LOG = Logger.instance("Environment");
|
||||
private static final List<String> blacklist = new ArrayList<>();
|
||||
public static File ROOT;
|
||||
public static File SYSROOT;
|
||||
public static File HOME;
|
||||
@@ -63,7 +63,7 @@ public final class Environment {
|
||||
* contains only the classes included in android.jar
|
||||
*/
|
||||
public static File COMPILER_MODULE;
|
||||
|
||||
|
||||
public static File INIT_SCRIPT;
|
||||
public static File PROJECT_DATA_FILE;
|
||||
public static File GRADLE_PROPS;
|
||||
@@ -73,193 +73,193 @@ public final class Environment {
|
||||
public static File SHELL;
|
||||
public static File LOGIN_SHELL;
|
||||
public static File BOOTCLASSPATH;
|
||||
|
||||
public static void init () {
|
||||
final BaseApplication app = BaseApplication.getBaseInstance ();
|
||||
ROOT = app.getIDEDataDir ();
|
||||
SYSROOT = mkdirIfNotExits (new File (app.getIDEDataDir (), "sysroot"));
|
||||
HOME = mkdirIfNotExits (app.getRootDir ());
|
||||
ANDROIDIDE_HOME = mkdirIfNotExits (new File (HOME, ".androidide"));
|
||||
TMP_DIR = mkdirIfNotExits (new File (SYSROOT, "tmp"));
|
||||
BIN_DIR = mkdirIfNotExits (new File (SYSROOT, "bin"));
|
||||
LIB_DIR = mkdirIfNotExits (new File (SYSROOT, "lib"));
|
||||
PROJECTS_DIR = mkdirIfNotExits (new File (FileUtil.getExternalStorageDir (), PROJECTS_FOLDER));
|
||||
COMPILER_MODULE = mkdirIfNotExits (new File (ANDROIDIDE_HOME, "compiler-module"));
|
||||
|
||||
IDE_PROPS_FILE = new File (SYSROOT, "etc/ide-environment.properties");
|
||||
LIB_HOOK = new File (LIB_DIR, "libhook.so");
|
||||
LIB_HOOK2 = new File (LIB_DIR, "libhook2.so");
|
||||
PROJECT_DATA_FILE = new File (TMP_DIR, "ide_project");
|
||||
|
||||
|
||||
public static void init() {
|
||||
final BaseApplication app = BaseApplication.getBaseInstance();
|
||||
ROOT = app.getIDEDataDir();
|
||||
SYSROOT = mkdirIfNotExits(new File(app.getIDEDataDir(), "sysroot"));
|
||||
HOME = mkdirIfNotExits(app.getRootDir());
|
||||
ANDROIDIDE_HOME = mkdirIfNotExits(new File(HOME, ".androidide"));
|
||||
TMP_DIR = mkdirIfNotExits(new File(SYSROOT, "tmp"));
|
||||
BIN_DIR = mkdirIfNotExits(new File(SYSROOT, "bin"));
|
||||
LIB_DIR = mkdirIfNotExits(new File(SYSROOT, "lib"));
|
||||
PROJECTS_DIR = mkdirIfNotExits(new File(FileUtil.getExternalStorageDir(), PROJECTS_FOLDER));
|
||||
COMPILER_MODULE = mkdirIfNotExits(new File(ANDROIDIDE_HOME, "compiler-module"));
|
||||
|
||||
IDE_PROPS_FILE = new File(SYSROOT, "etc/ide-environment.properties");
|
||||
LIB_HOOK = new File(LIB_DIR, "libhook.so");
|
||||
LIB_HOOK2 = new File(LIB_DIR, "libhook2.so");
|
||||
PROJECT_DATA_FILE = new File(TMP_DIR, "ide_project");
|
||||
|
||||
INIT_SCRIPT =
|
||||
new File (
|
||||
mkdirIfNotExits (new File (app.getIDEDataDir (), "init")),
|
||||
new File(
|
||||
mkdirIfNotExits(new File(app.getIDEDataDir(), "init")),
|
||||
"data/common/androidide.init.gradle");
|
||||
BOOTCLASSPATH = new File ("");
|
||||
GRADLE_USER_HOME = new File (HOME, ".gradle");
|
||||
GRADLE_PROPS = new File (GRADLE_USER_HOME, "gradle.properties");
|
||||
|
||||
IDE_PROPS.putAll (readProperties ());
|
||||
ANDROID_HOME = new File (readProp ("ANDROID_HOME", DEFAULT_ANDROID_HOME));
|
||||
JAVA_HOME = new File (readProp ("JAVA_HOME", DEFAULT_JAVA_HOME));
|
||||
|
||||
JAVA = new File (JAVA_HOME, "bin/java");
|
||||
BUSYBOX = new File (BIN_DIR, "busybox");
|
||||
SHELL = new File (BIN_DIR, "bash");
|
||||
LOGIN_SHELL = new File (BIN_DIR, "login");
|
||||
|
||||
setExecutable (JAVA);
|
||||
setExecutable (BUSYBOX);
|
||||
setExecutable (SHELL);
|
||||
|
||||
System.setProperty ("user.home", HOME.getAbsolutePath ());
|
||||
System.setProperty ("java.home", JAVA_HOME.getAbsolutePath ());
|
||||
BOOTCLASSPATH = new File("");
|
||||
GRADLE_USER_HOME = new File(HOME, ".gradle");
|
||||
GRADLE_PROPS = new File(GRADLE_USER_HOME, "gradle.properties");
|
||||
|
||||
IDE_PROPS.putAll(readProperties());
|
||||
ANDROID_HOME = new File(readProp("ANDROID_HOME", DEFAULT_ANDROID_HOME));
|
||||
JAVA_HOME = new File(readProp("JAVA_HOME", DEFAULT_JAVA_HOME));
|
||||
|
||||
JAVA = new File(JAVA_HOME, "bin/java");
|
||||
BUSYBOX = new File(BIN_DIR, "busybox");
|
||||
SHELL = new File(BIN_DIR, "bash");
|
||||
LOGIN_SHELL = new File(BIN_DIR, "login");
|
||||
|
||||
setExecutable(JAVA);
|
||||
setExecutable(BUSYBOX);
|
||||
setExecutable(SHELL);
|
||||
|
||||
System.setProperty("user.home", HOME.getAbsolutePath());
|
||||
System.setProperty("java.home", JAVA_HOME.getAbsolutePath());
|
||||
}
|
||||
|
||||
public static void setExecutable (@NonNull final File file) {
|
||||
if (!file.setExecutable (true)) {
|
||||
LOG.error ("Unable to set executable permissions to file", file);
|
||||
|
||||
public static void setExecutable(@NonNull final File file) {
|
||||
if (!file.setExecutable(true)) {
|
||||
LOG.error("Unable to set executable permissions to file", file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private static Map<String, String> readProperties () {
|
||||
final Map<String, String> props = new HashMap<> ();
|
||||
if (IDE_PROPS_FILE == null || !IDE_PROPS_FILE.exists ()) {
|
||||
private static Map<String, String> readProperties() {
|
||||
final Map<String, String> props = new HashMap<>();
|
||||
if (IDE_PROPS_FILE == null || !IDE_PROPS_FILE.exists()) {
|
||||
return props;
|
||||
}
|
||||
try {
|
||||
Properties p = new Properties ();
|
||||
p.load (new StringReader (FileIOUtils.readFile2String (IDE_PROPS_FILE)));
|
||||
for (@SuppressWarnings("rawtypes") Map.Entry entry : p.entrySet ()) {
|
||||
props.put (entry.getKey () + "", entry.getValue () + "");
|
||||
Properties p = new Properties();
|
||||
p.load(new StringReader(FileIOUtils.readFile2String(IDE_PROPS_FILE)));
|
||||
for (@SuppressWarnings("rawtypes") Map.Entry entry : p.entrySet()) {
|
||||
props.put(entry.getKey() + "", entry.getValue() + "");
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
LOG.error ("Unable to read properties file", th);
|
||||
LOG.error("Unable to read properties file", th);
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
public static void setBootClasspath (@NonNull File file) {
|
||||
BOOTCLASSPATH = new File (file.getAbsolutePath ());
|
||||
|
||||
public static void setBootClasspath(@NonNull File file) {
|
||||
BOOTCLASSPATH = new File(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
public static Map<String, String> getEnvironment () {
|
||||
|
||||
if (!ENV_VARS.isEmpty ()) {
|
||||
|
||||
public static Map<String, String> getEnvironment() {
|
||||
|
||||
if (!ENV_VARS.isEmpty()) {
|
||||
return ENV_VARS;
|
||||
}
|
||||
|
||||
ENV_VARS.put ("HOME", HOME.getAbsolutePath ());
|
||||
ENV_VARS.put ("ANDROID_HOME", ANDROID_HOME.getAbsolutePath ());
|
||||
ENV_VARS.put ("JAVA_HOME", JAVA_HOME.getAbsolutePath ());
|
||||
ENV_VARS.put ("GRADLE_USER_HOME", GRADLE_USER_HOME.getAbsolutePath ());
|
||||
ENV_VARS.put ("TMPDIR", TMP_DIR.getAbsolutePath ());
|
||||
ENV_VARS.put ("PROJECTS", PROJECTS_DIR.getAbsolutePath ());
|
||||
ENV_VARS.put ("LANG", "en_US.UTF-8");
|
||||
ENV_VARS.put ("LC_ALL", "en_US.UTF-8");
|
||||
|
||||
ENV_VARS.put ("SYSROOT", SYSROOT.getAbsolutePath ());
|
||||
|
||||
ENV_VARS.put ("BUSYBOX", BUSYBOX.getAbsolutePath ());
|
||||
ENV_VARS.put ("SHELL", SHELL.getAbsolutePath ());
|
||||
ENV_VARS.put ("CONFIG_SHELL", SHELL.getAbsolutePath ());
|
||||
ENV_VARS.put ("TERM", "screen");
|
||||
|
||||
|
||||
ENV_VARS.put("HOME", HOME.getAbsolutePath());
|
||||
ENV_VARS.put("ANDROID_HOME", ANDROID_HOME.getAbsolutePath());
|
||||
ENV_VARS.put("JAVA_HOME", JAVA_HOME.getAbsolutePath());
|
||||
ENV_VARS.put("GRADLE_USER_HOME", GRADLE_USER_HOME.getAbsolutePath());
|
||||
ENV_VARS.put("TMPDIR", TMP_DIR.getAbsolutePath());
|
||||
ENV_VARS.put("PROJECTS", PROJECTS_DIR.getAbsolutePath());
|
||||
ENV_VARS.put("LANG", "en_US.UTF-8");
|
||||
ENV_VARS.put("LC_ALL", "en_US.UTF-8");
|
||||
|
||||
ENV_VARS.put("SYSROOT", SYSROOT.getAbsolutePath());
|
||||
|
||||
ENV_VARS.put("BUSYBOX", BUSYBOX.getAbsolutePath());
|
||||
ENV_VARS.put("SHELL", SHELL.getAbsolutePath());
|
||||
ENV_VARS.put("CONFIG_SHELL", SHELL.getAbsolutePath());
|
||||
ENV_VARS.put("TERM", "screen");
|
||||
|
||||
// If LD_LIBRARY_PATH is set, append $SYSROOT/lib to it,
|
||||
// else set it to $SYSROOT/lib
|
||||
String ld = System.getenv ("LD_LIBRARY_PATH");
|
||||
if (ld == null || ld.trim ().length () <= 0) {
|
||||
String ld = System.getenv("LD_LIBRARY_PATH");
|
||||
if (ld == null || ld.trim().length() <= 0) {
|
||||
ld = "";
|
||||
} else {
|
||||
ld += File.pathSeparator;
|
||||
}
|
||||
ld += LIB_DIR.getAbsolutePath ();
|
||||
ENV_VARS.put ("LD_LIBRARY_PATH", ld);
|
||||
|
||||
ld += LIB_DIR.getAbsolutePath();
|
||||
ENV_VARS.put("LD_LIBRARY_PATH", ld);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
|
||||
&& BaseApplication.isAarch64 ()
|
||||
&& LIB_HOOK.exists ()) {
|
||||
&& BaseApplication.isAarch64()
|
||||
&& LIB_HOOK.exists()) {
|
||||
// Required for JDK 11
|
||||
ENV_VARS.put ("LD_PRELOAD", LIB_HOOK.getAbsolutePath ());
|
||||
ENV_VARS.put("LD_PRELOAD", LIB_HOOK.getAbsolutePath());
|
||||
}
|
||||
|
||||
addToEnvIfPresent (ENV_VARS, "ANDROID_ART_ROOT");
|
||||
addToEnvIfPresent (ENV_VARS, "DEX2OATBOOTCLASSPATH");
|
||||
addToEnvIfPresent (ENV_VARS, "ANDROID_I18N_ROOT");
|
||||
addToEnvIfPresent (ENV_VARS, "ANDROID_RUNTIME_ROOT");
|
||||
addToEnvIfPresent (ENV_VARS, "ANDROID_TZDATA_ROOT");
|
||||
addToEnvIfPresent (ENV_VARS, "ANDROID_DATA");
|
||||
addToEnvIfPresent (ENV_VARS, "ANDROID_ROOT");
|
||||
|
||||
String path = createPath ();
|
||||
|
||||
ENV_VARS.put ("PATH", path);
|
||||
|
||||
for (String key : IDE_PROPS.keySet ()) {
|
||||
if (!blacklistedVariables ().contains (key.trim ())) {
|
||||
ENV_VARS.put (key, readProp (key, ""));
|
||||
|
||||
addToEnvIfPresent(ENV_VARS, "ANDROID_ART_ROOT");
|
||||
addToEnvIfPresent(ENV_VARS, "DEX2OATBOOTCLASSPATH");
|
||||
addToEnvIfPresent(ENV_VARS, "ANDROID_I18N_ROOT");
|
||||
addToEnvIfPresent(ENV_VARS, "ANDROID_RUNTIME_ROOT");
|
||||
addToEnvIfPresent(ENV_VARS, "ANDROID_TZDATA_ROOT");
|
||||
addToEnvIfPresent(ENV_VARS, "ANDROID_DATA");
|
||||
addToEnvIfPresent(ENV_VARS, "ANDROID_ROOT");
|
||||
|
||||
String path = createPath();
|
||||
|
||||
ENV_VARS.put("PATH", path);
|
||||
|
||||
for (String key : IDE_PROPS.keySet()) {
|
||||
if (!blacklistedVariables().contains(key.trim())) {
|
||||
ENV_VARS.put(key, readProp(key, ""));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ENV_VARS;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private static String createPath () {
|
||||
private static String createPath() {
|
||||
String path = "";
|
||||
path += String.format ("%s/bin", JAVA_HOME.getAbsolutePath ());
|
||||
path += String.format (":%s/cmdline-tools/latest/bin", ANDROID_HOME.getAbsolutePath ());
|
||||
path += String.format (":%s/cmake/bin", ANDROID_HOME.getAbsolutePath ());
|
||||
path += String.format (":%s/bin", SYSROOT.getAbsolutePath ());
|
||||
path += String.format (":%s", System.getenv ("PATH"));
|
||||
path += String.format("%s/bin", JAVA_HOME.getAbsolutePath());
|
||||
path += String.format(":%s/cmdline-tools/latest/bin", ANDROID_HOME.getAbsolutePath());
|
||||
path += String.format(":%s/cmake/bin", ANDROID_HOME.getAbsolutePath());
|
||||
path += String.format(":%s/bin", SYSROOT.getAbsolutePath());
|
||||
path += String.format(":%s", System.getenv("PATH"));
|
||||
return path;
|
||||
}
|
||||
|
||||
public static void addToEnvIfPresent (Map<String, String> environment, String name) {
|
||||
String value = System.getenv (name);
|
||||
|
||||
public static void addToEnvIfPresent(Map<String, String> environment, String name) {
|
||||
String value = System.getenv(name);
|
||||
if (value != null) {
|
||||
environment.put (name, value);
|
||||
environment.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static String readProp (String key, String defaultValue) {
|
||||
String value = IDE_PROPS.getOrDefault (key, defaultValue);
|
||||
|
||||
public static String readProp(String key, String defaultValue) {
|
||||
String value = IDE_PROPS.getOrDefault(key, defaultValue);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (value.contains ("$HOME")) {
|
||||
value = value.replace ("$HOME", HOME.getAbsolutePath ());
|
||||
if (value.contains("$HOME")) {
|
||||
value = value.replace("$HOME", HOME.getAbsolutePath());
|
||||
}
|
||||
if (value.contains ("$SYSROOT")) {
|
||||
value = value.replace ("$SYSROOT", SYSROOT.getAbsolutePath ());
|
||||
if (value.contains("$SYSROOT")) {
|
||||
value = value.replace("$SYSROOT", SYSROOT.getAbsolutePath());
|
||||
}
|
||||
if (value.contains ("$PATH")) {
|
||||
value = value.replace ("$PATH", createPath ());
|
||||
if (value.contains("$PATH")) {
|
||||
value = value.replace("$PATH", createPath());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static File mkdirIfNotExits (File in) {
|
||||
if (in != null && !in.exists ()) {
|
||||
FileUtils.createOrExistsDir (in);
|
||||
|
||||
public static File mkdirIfNotExits(File in) {
|
||||
if (in != null && !in.exists()) {
|
||||
FileUtils.createOrExistsDir(in);
|
||||
}
|
||||
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public static boolean isCompilerModuleInstalled () {
|
||||
final var modules = new File (COMPILER_MODULE, "lib/modules");
|
||||
final var release = new File (COMPILER_MODULE, "release");
|
||||
return modules.exists () && modules.isFile () && release.exists () && release.isFile ();
|
||||
public static boolean isCompilerModuleInstalled() {
|
||||
final var modules = new File(COMPILER_MODULE, "lib/modules");
|
||||
final var release = new File(COMPILER_MODULE, "release");
|
||||
return modules.exists() && modules.isFile() && release.exists() && release.isFile();
|
||||
}
|
||||
|
||||
private static List<String> blacklistedVariables () {
|
||||
if (blacklist.isEmpty ()) {
|
||||
blacklist.add ("HOME");
|
||||
blacklist.add ("SYSROOT");
|
||||
blacklist.add ("JLS_HOME");
|
||||
|
||||
private static List<String> blacklistedVariables() {
|
||||
if (blacklist.isEmpty()) {
|
||||
blacklist.add("HOME");
|
||||
blacklist.add("SYSROOT");
|
||||
blacklist.add("JLS_HOME");
|
||||
}
|
||||
return blacklist;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ext {
|
||||
common = [
|
||||
editor: 'io.github.Rosemoe.sora-editor:editor:0.10.2',
|
||||
editor: 'io.github.Rosemoe.sora-editor:editor:0.10.7',
|
||||
utilcode: 'com.blankj:utilcodex:1.30.6',
|
||||
file_picker: 'com.github.abhishekti7:UnicornFilePicker:1.0.2',
|
||||
glide: 'com.github.bumptech.glide:glide:4.12.0',
|
||||
|
||||
@@ -32,37 +32,37 @@ import java.util.Objects;
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class FrameworkValues {
|
||||
|
||||
|
||||
@NonNull
|
||||
public static List<String> listDimens () {
|
||||
return listFields (android.R.dimen.class);
|
||||
public static List<String> listDimens() {
|
||||
return listFields(android.R.dimen.class);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static List<String> listStrings () {
|
||||
return listFields (android.R.string.class);
|
||||
public static List<String> listStrings() {
|
||||
return listFields(android.R.string.class);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static List<String> listColors () {
|
||||
return listFields (android.R.color.class);
|
||||
public static List<String> listColors() {
|
||||
return listFields(android.R.color.class);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private static List<String> listFields (final Class<?> klass) {
|
||||
Objects.requireNonNull (klass);
|
||||
|
||||
final var list = new ArrayList<String> ();
|
||||
final var fields = klass.getDeclaredFields ();
|
||||
private static List<String> listFields(final Class<?> klass) {
|
||||
Objects.requireNonNull(klass);
|
||||
|
||||
final var list = new ArrayList<String>();
|
||||
final var fields = klass.getDeclaredFields();
|
||||
for (var field : fields) {
|
||||
final var mods = field.getModifiers ();
|
||||
if (!isPublic (mods) || !isStatic (mods)) {
|
||||
final var mods = field.getModifiers();
|
||||
if (!isPublic(mods) || !isStatic(mods)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add (field.getName ());
|
||||
|
||||
list.add(field.getName());
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ import java.util.Objects;
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class ValuesTable {
|
||||
|
||||
private static final Logger LOG = Logger.instance ("ValuesTable");
|
||||
|
||||
private static final Logger LOG = Logger.instance("ValuesTable");
|
||||
// TODO Parse styles and styleables
|
||||
private final Map<String, IResource> arrays;
|
||||
private final Map<String, IResource> strings;
|
||||
@@ -57,185 +57,185 @@ public class ValuesTable {
|
||||
private final Map<String, IResource> integers;
|
||||
private final Map<String, IResource> dimens;
|
||||
private final Map<String, IResource> booleans;
|
||||
|
||||
private final Map<String, Map<String, IResource>> resourceMap = new HashMap<> ();
|
||||
|
||||
protected ValuesTable () {
|
||||
this.arrays = new HashMap<> ();
|
||||
this.strings = new HashMap<> ();
|
||||
this.colors = new HashMap<> ();
|
||||
this.integers = new HashMap<> ();
|
||||
this.dimens = new HashMap<> ();
|
||||
this.booleans = new HashMap<> ();
|
||||
|
||||
this.resourceMap.put ("array", this.arrays);
|
||||
this.resourceMap.put ("string", this.strings);
|
||||
this.resourceMap.put ("color", this.colors);
|
||||
this.resourceMap.put ("integer", this.integers);
|
||||
this.resourceMap.put ("dimen", this.dimens);
|
||||
this.resourceMap.put ("bool", this.booleans);
|
||||
|
||||
private final Map<String, Map<String, IResource>> resourceMap = new HashMap<>();
|
||||
|
||||
protected ValuesTable() {
|
||||
this.arrays = new HashMap<>();
|
||||
this.strings = new HashMap<>();
|
||||
this.colors = new HashMap<>();
|
||||
this.integers = new HashMap<>();
|
||||
this.dimens = new HashMap<>();
|
||||
this.booleans = new HashMap<>();
|
||||
|
||||
this.resourceMap.put("array", this.arrays);
|
||||
this.resourceMap.put("string", this.strings);
|
||||
this.resourceMap.put("color", this.colors);
|
||||
this.resourceMap.put("integer", this.integers);
|
||||
this.resourceMap.put("dimen", this.dimens);
|
||||
this.resourceMap.put("bool", this.booleans);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new table by reading the files from the given values directory.
|
||||
*
|
||||
* @param valuesDirectory The "res/values" directory.
|
||||
* @return The values table or {@code null} if the directory is invalid or there are no files in
|
||||
* this directory.
|
||||
* this directory.
|
||||
* @throws XmlPullParserException Thrown by {@link XmlPullParserFactory}.
|
||||
* @throws IOException Thrown by {@link XmlPullParser}.
|
||||
* @throws IOException Thrown by {@link XmlPullParser}.
|
||||
*/
|
||||
@Nullable
|
||||
public static ValuesTable forDirectory (File valuesDirectory) throws Exception {
|
||||
public static ValuesTable forDirectory(File valuesDirectory) throws Exception {
|
||||
if (valuesDirectory == null) {
|
||||
LOG.error ("Cannot create values table for directory: ", null);
|
||||
LOG.error("Cannot create values table for directory: ", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!valuesDirectory.exists ()) {
|
||||
LOG.error (
|
||||
|
||||
if (!valuesDirectory.exists()) {
|
||||
LOG.error(
|
||||
"Cannot create values table for directory as it does not exists. Directory:",
|
||||
valuesDirectory);
|
||||
return null;
|
||||
}
|
||||
|
||||
final var files = valuesDirectory.listFiles (ValuesTable::isValid);
|
||||
|
||||
final var files = valuesDirectory.listFiles(ValuesTable::isValid);
|
||||
if (files == null) {
|
||||
LOG.error ("No files found in the given values directory");
|
||||
LOG.error("No files found in the given values directory");
|
||||
return null;
|
||||
}
|
||||
|
||||
final var start = System.currentTimeMillis ();
|
||||
final var values = new ValuesTable ();
|
||||
|
||||
|
||||
final var start = System.currentTimeMillis();
|
||||
final var values = new ValuesTable();
|
||||
|
||||
for (var file : files) {
|
||||
final var factory = XmlPullParserFactory.newInstance ();
|
||||
final var parser = factory.newPullParser ();
|
||||
parser.setInput (new FileInputStream (file), null);
|
||||
|
||||
var event = parser.getEventType ();
|
||||
final var factory = XmlPullParserFactory.newInstance();
|
||||
final var parser = factory.newPullParser();
|
||||
parser.setInput(new FileInputStream(file), null);
|
||||
|
||||
var event = parser.getEventType();
|
||||
while (event != XmlPullParser.END_DOCUMENT) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
final var tag = parser.getName ();
|
||||
if ("resources".equals (tag)) {
|
||||
event = parser.next ();
|
||||
final var tag = parser.getName();
|
||||
if ("resources".equals(tag)) {
|
||||
event = parser.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
readTag (tag, parser, values);
|
||||
|
||||
readTag(tag, parser, values);
|
||||
}
|
||||
event = parser.next ();
|
||||
event = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
final var duration = System.currentTimeMillis () - start;
|
||||
LOG.info (
|
||||
String.format (
|
||||
Locale.getDefault (),
|
||||
|
||||
final var duration = System.currentTimeMillis() - start;
|
||||
LOG.info(
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
"Took %d ms to read %d files in directory: %s",
|
||||
duration,
|
||||
files.length,
|
||||
valuesDirectory));
|
||||
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static void readTag (String tag, XmlPullParser parser, ValuesTable values)
|
||||
|
||||
private static void readTag(String tag, XmlPullParser parser, ValuesTable values)
|
||||
throws Exception {
|
||||
|
||||
if ("style".equals (tag) || "declare-styleable".equals (tag)) {
|
||||
|
||||
if ("style".equals(tag) || "declare-styleable".equals(tag)) {
|
||||
// These tags are not supported yet
|
||||
// Skip parsing until we reach next tag with same depth as of this tag
|
||||
skip (parser);
|
||||
skip(parser);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TODO Should we check if these tags are specified within <resources>?
|
||||
final var name = getName (parser);
|
||||
final var name = getName(parser);
|
||||
if (name == null) {
|
||||
LOG.error (String.format ("A <%s> resource was found with no 'name' attribute", tag));
|
||||
LOG.error(String.format("A <%s> resource was found with no 'name' attribute", tag));
|
||||
return;
|
||||
}
|
||||
|
||||
if ("item".equals (tag)) {
|
||||
tag = parser.getAttributeValue (null, "type");
|
||||
|
||||
if ("item".equals(tag)) {
|
||||
tag = parser.getAttributeValue(null, "type");
|
||||
if (tag == null) {
|
||||
LOG.error ("<item> resource value found but no 'type' was specified.");
|
||||
LOG.error("<item> resource value found but no 'type' was specified.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check for array before reading value
|
||||
// because array resources do not have text values
|
||||
if ("array".equals (tag) || tag.endsWith ("-array")) {
|
||||
readArray (parser, values, name);
|
||||
if ("array".equals(tag) || tag.endsWith("-array")) {
|
||||
readArray(parser, values, name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Value must be read after all other required values have been read
|
||||
final var value = parser.nextText ();
|
||||
final var value = parser.nextText();
|
||||
IResource resourceValue;
|
||||
|
||||
|
||||
switch (tag) {
|
||||
case "string":
|
||||
resourceValue = new StringResource (name, value);
|
||||
values.strings.put (name, resourceValue);
|
||||
resourceValue = new StringResource(name, value);
|
||||
values.strings.put(name, resourceValue);
|
||||
break;
|
||||
case "color":
|
||||
resourceValue = new ColorResource (name, value);
|
||||
values.colors.put (name, resourceValue);
|
||||
resourceValue = new ColorResource(name, value);
|
||||
values.colors.put(name, resourceValue);
|
||||
break;
|
||||
case "bool":
|
||||
resourceValue = new BooleanResource (name, value);
|
||||
values.booleans.put (name, resourceValue);
|
||||
resourceValue = new BooleanResource(name, value);
|
||||
values.booleans.put(name, resourceValue);
|
||||
break;
|
||||
case "dimen":
|
||||
resourceValue = new DimensionResource (name, value);
|
||||
values.dimens.put (name, resourceValue);
|
||||
resourceValue = new DimensionResource(name, value);
|
||||
values.dimens.put(name, resourceValue);
|
||||
break;
|
||||
case "integer":
|
||||
resourceValue = new IntegerResource (name, value);
|
||||
values.integers.put (name, resourceValue);
|
||||
resourceValue = new IntegerResource(name, value);
|
||||
values.integers.put(name, resourceValue);
|
||||
break;
|
||||
default:
|
||||
LOG.warn ("Unknown or unsupported resource value tag:", tag);
|
||||
LOG.warn("Unknown or unsupported resource value tag:", tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void readArray (@NonNull XmlPullParser parser, ValuesTable values, String name)
|
||||
|
||||
private static void readArray(@NonNull XmlPullParser parser, ValuesTable values, String name)
|
||||
throws XmlPullParserException, IOException {
|
||||
final var minDepth = parser.getDepth ();
|
||||
final var items = new ArrayList<String> ();
|
||||
|
||||
var event = parser.getEventType ();
|
||||
while ((event = parser.next ()) != XmlPullParser.END_DOCUMENT
|
||||
&& parser.getDepth () >= minDepth) {
|
||||
final var minDepth = parser.getDepth();
|
||||
final var items = new ArrayList<String>();
|
||||
|
||||
var event = parser.getEventType();
|
||||
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& parser.getDepth() >= minDepth) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
final var child = parser.getName ();
|
||||
if ("item".equals (child)) {
|
||||
final var value = parser.nextText ();
|
||||
items.add (value);
|
||||
final var child = parser.getName();
|
||||
if ("item".equals(child)) {
|
||||
final var value = parser.nextText();
|
||||
items.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final var arr = new String[items.size ()];
|
||||
|
||||
final var arr = new String[items.size()];
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = items.get (i);
|
||||
arr[i] = items.get(i);
|
||||
}
|
||||
|
||||
values.arrays.put (name, new ArrayResource (name, arr));
|
||||
|
||||
values.arrays.put(name, new ArrayResource(name, arr));
|
||||
}
|
||||
|
||||
private static void skip (@NonNull XmlPullParser parser)
|
||||
|
||||
private static void skip(@NonNull XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
if (parser.getEventType () != XmlPullParser.START_TAG) {
|
||||
throw new IllegalStateException ();
|
||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
int depth = 1;
|
||||
while (depth != 0) {
|
||||
switch (parser.next ()) {
|
||||
switch (parser.next()) {
|
||||
case XmlPullParser.END_TAG:
|
||||
depth--;
|
||||
break;
|
||||
@@ -245,21 +245,21 @@ public class ValuesTable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getName (@NonNull XmlPullParser parser) {
|
||||
return parser.getAttributeValue (null, "name");
|
||||
|
||||
private static String getName(@NonNull XmlPullParser parser) {
|
||||
return parser.getAttributeValue(null, "name");
|
||||
}
|
||||
|
||||
private static boolean isValid (File file) {
|
||||
return file != null && file.isFile () && FileUtils.isUtf8 (file);
|
||||
|
||||
private static boolean isValid(File file) {
|
||||
return file != null && file.isFile() && FileUtils.isUtf8(file);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public Map<String, IResource> getTable (final String name) {
|
||||
Objects.requireNonNull (name);
|
||||
return this.resourceMap.get (name);
|
||||
public Map<String, IResource> getTable(final String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return this.resourceMap.get(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds a resource value of any type.
|
||||
*
|
||||
@@ -267,133 +267,133 @@ public class ValuesTable {
|
||||
* @return The resource value or {@code null} if there is no resource with the given name.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public IResource findResource (final String name) {
|
||||
public IResource findResource(final String name) {
|
||||
IResource value;
|
||||
|
||||
value = findString (name);
|
||||
|
||||
value = findString(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = findColor (name);
|
||||
|
||||
value = findColor(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = findInteger (name);
|
||||
|
||||
value = findInteger(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = findDimension (name);
|
||||
|
||||
value = findDimension(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = findArray (name);
|
||||
|
||||
value = findArray(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = findBoolean (name);
|
||||
|
||||
value = findBoolean(name);
|
||||
//noinspection RedundantIfStatement
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayResource findArray (final String name) {
|
||||
return (ArrayResource) arrays.getOrDefault (name, null);
|
||||
|
||||
public ArrayResource findArray(final String name) {
|
||||
return (ArrayResource) arrays.getOrDefault(name, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a string value with the given name.
|
||||
*
|
||||
* @param name The name of the string resource.
|
||||
* @return The string resource or {@code null} if there is no resource with the given name.
|
||||
*/
|
||||
public StringResource findString (final String name) {
|
||||
return (StringResource) strings.getOrDefault (name, null);
|
||||
public StringResource findString(final String name) {
|
||||
return (StringResource) strings.getOrDefault(name, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a color value with the given name.
|
||||
*
|
||||
* @param name The name of the color resource.
|
||||
* @return The color resource or {@code null} if there is no resource with the given name.
|
||||
*/
|
||||
public ColorResource findColor (final String name) {
|
||||
return (ColorResource) colors.getOrDefault (name, null);
|
||||
public ColorResource findColor(final String name) {
|
||||
return (ColorResource) colors.getOrDefault(name, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a integer value with the given name.
|
||||
*
|
||||
* @param name The name of the integer resource.
|
||||
* @return The integer resource or {@code null} if there is no resource with the given name.
|
||||
*/
|
||||
public IntegerResource findInteger (final String name) {
|
||||
return (IntegerResource) integers.getOrDefault (name, null);
|
||||
public IntegerResource findInteger(final String name) {
|
||||
return (IntegerResource) integers.getOrDefault(name, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a dimension value with the given name.
|
||||
*
|
||||
* @param name The name of the dimension resource.
|
||||
* @return The dimension resource or {@code null} if there is no resource with the given name.
|
||||
*/
|
||||
public DimensionResource findDimension (final String name) {
|
||||
return (DimensionResource) dimens.getOrDefault (name, null);
|
||||
public DimensionResource findDimension(final String name) {
|
||||
return (DimensionResource) dimens.getOrDefault(name, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a boolean value with the given name.
|
||||
*
|
||||
* @param name The name of the boolean resource.
|
||||
* @return The boolean resource or {@code null} if there is no resource with the given name.
|
||||
*/
|
||||
public BooleanResource findBoolean (final String name) {
|
||||
return (BooleanResource) booleans.getOrDefault (name, null);
|
||||
public BooleanResource findBoolean(final String name) {
|
||||
return (BooleanResource) booleans.getOrDefault(name, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the contents of the given file and updates this table.
|
||||
*
|
||||
* @param file The file to sync with.
|
||||
*/
|
||||
public void syncWithFile (final File file) throws Exception {
|
||||
final var start = System.currentTimeMillis ();
|
||||
final var factory = XmlPullParserFactory.newInstance ();
|
||||
final var parser = factory.newPullParser ();
|
||||
parser.setInput (new FileInputStream (file), null);
|
||||
|
||||
var event = parser.getEventType ();
|
||||
public void syncWithFile(final File file) throws Exception {
|
||||
final var start = System.currentTimeMillis();
|
||||
final var factory = XmlPullParserFactory.newInstance();
|
||||
final var parser = factory.newPullParser();
|
||||
parser.setInput(new FileInputStream(file), null);
|
||||
|
||||
var event = parser.getEventType();
|
||||
while (event != XmlPullParser.END_DOCUMENT) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
final var tag = parser.getName ();
|
||||
if ("resources".equals (tag)) {
|
||||
event = parser.next ();
|
||||
final var tag = parser.getName();
|
||||
if ("resources".equals(tag)) {
|
||||
event = parser.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
ValuesTable.readTag (tag, parser, this);
|
||||
|
||||
ValuesTable.readTag(tag, parser, this);
|
||||
}
|
||||
event = parser.next ();
|
||||
event = parser.next();
|
||||
}
|
||||
|
||||
LOG.debug (
|
||||
|
||||
LOG.debug(
|
||||
"Syncing with file",
|
||||
file.getName (),
|
||||
file.getName(),
|
||||
"took",
|
||||
(System.currentTimeMillis () - start),
|
||||
(System.currentTimeMillis() - start),
|
||||
"ms");
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString () {
|
||||
public String toString() {
|
||||
return "ValuesTable{"
|
||||
+ "strings="
|
||||
+ strings
|
||||
|
||||
@@ -31,110 +31,109 @@ import java.util.regex.Pattern;
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class ValuesTableFactory {
|
||||
|
||||
private static final Map<File, ValuesTable> valueTables = new HashMap<> ();
|
||||
private static final Logger LOG = Logger.instance ("ValuesTableFactory");
|
||||
|
||||
public static ValuesTable getTable (final File resDir) {
|
||||
return valueTables.getOrDefault (resDir, null);
|
||||
|
||||
private static final Map<File, ValuesTable> valueTables = new HashMap<>();
|
||||
private static final Logger LOG = Logger.instance("ValuesTableFactory");
|
||||
|
||||
public static ValuesTable getTable(final File resDir) {
|
||||
return valueTables.getOrDefault(resDir, null);
|
||||
}
|
||||
|
||||
public static Map<File, ValuesTable> getAllTables () {
|
||||
|
||||
public static Map<File, ValuesTable> getAllTables() {
|
||||
return valueTables;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup this ValuesTableFactory with the given "res" directories.
|
||||
*
|
||||
* @param resDirs The resource directories.
|
||||
*/
|
||||
public static void setupWithResDirectories (File... resDirs) {
|
||||
|
||||
public static void setupWithResDirectories(File... resDirs) {
|
||||
|
||||
if (resDirs == null || resDirs.length <= 0) {
|
||||
LOG.error ("Cannot create value tables. No directories were specified.");
|
||||
LOG.error("Cannot create value tables. No directories were specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
valueTables.clear ();
|
||||
|
||||
final var start = System.currentTimeMillis ();
|
||||
|
||||
valueTables.clear();
|
||||
|
||||
final var start = System.currentTimeMillis();
|
||||
for (var res : resDirs) {
|
||||
if (res == null || !res.exists ()) {
|
||||
if (res == null || !res.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final var table = createTable (res);
|
||||
|
||||
final var table = createTable(res);
|
||||
if (table == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
valueTables.put (res, table);
|
||||
|
||||
valueTables.put(res, table);
|
||||
}
|
||||
|
||||
LOG.debug (
|
||||
String.format (
|
||||
Locale.getDefault (),
|
||||
|
||||
LOG.debug(
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
"Created value tables for %d resource directories in %d ms",
|
||||
resDirs.length,
|
||||
(System.currentTimeMillis () - start)));
|
||||
(System.currentTimeMillis() - start)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify that the given file's contents were changed and the corresponding table must be
|
||||
* updated with new values.
|
||||
*
|
||||
* @param file The file that was changed.
|
||||
*/
|
||||
public static void syncWithFile (final File file) {
|
||||
public static void syncWithFile(final File file) {
|
||||
if (file == null) {
|
||||
LOG.error ("Cannot update value tables. Given file is null.");
|
||||
LOG.error("Cannot update value tables. Given file is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
final var pattern = Pattern.compile (".*/src/.*/res/values/(\\w|_)+\\.xml");
|
||||
if (!pattern.matcher (file.getAbsolutePath ()).matches ()) {
|
||||
|
||||
final var pattern = Pattern.compile(".*/src/.*/res/values/(\\w|_)+\\.xml");
|
||||
if (!pattern.matcher(file.getAbsolutePath()).matches()) {
|
||||
// This file is not a values resource file.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final var resDir =
|
||||
Objects.requireNonNull (file.getParentFile ()) /* values dir */
|
||||
.getParentFile () /* res dir*/;
|
||||
var table = valueTables.getOrDefault (resDir, null);
|
||||
Objects.requireNonNull(file.getParentFile()) /* values dir */
|
||||
.getParentFile() /* res dir*/;
|
||||
var table = valueTables.getOrDefault(resDir, null);
|
||||
if (table == null) {
|
||||
table = createTable (resDir);
|
||||
table = createTable(resDir);
|
||||
if (table != null) {
|
||||
valueTables.put (resDir, table);
|
||||
valueTables.put(resDir, table);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
table.syncWithFile (file);
|
||||
table.syncWithFile(file);
|
||||
} catch (Throwable e) {
|
||||
LOG.error ("Failed to sync values table", e);
|
||||
LOG.error("Failed to sync values table", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static ValuesTable createTable (File res) {
|
||||
|
||||
private static ValuesTable createTable(File res) {
|
||||
try {
|
||||
final var values = new File (res, "values");
|
||||
if (!values.exists ()) {
|
||||
final var values = new File(res, "values");
|
||||
if (!values.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var table = ValuesTable.forDirectory (values);
|
||||
|
||||
var table = ValuesTable.forDirectory(values);
|
||||
if (table == null) {
|
||||
throw new ParseException ();
|
||||
throw new ParseException();
|
||||
}
|
||||
|
||||
|
||||
return table;
|
||||
} catch (Throwable e) {
|
||||
LOG.error ("Failed to create values table", e);
|
||||
LOG.error("Failed to create values table", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class ParseException extends RuntimeException {
|
||||
}
|
||||
|
||||
static class ParseException extends RuntimeException {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user