Merge pull request #219 from MrIkso/main

Fixed 'SuperNotCalledException' in DesignerActivity
Call onDestroy in all activities removing reference to bindings
Added log filter features (fixes #74).
This commit is contained in:
Akash Yadav
2022-06-17 19:01:31 +05:30
committed by GitHub
17 changed files with 578 additions and 398 deletions
@@ -184,4 +184,10 @@ public class AboutActivity extends StudioActivity {
return getString(R.string.about_footer_alternate, arch);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
}
}
@@ -56,4 +56,10 @@ public class CrashHandlerActivity extends StudioActivity {
.addToBackStack(null)
.commit();
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
}
}
@@ -294,6 +294,7 @@ public class DesignerActivity extends StudioActivity
@Override
protected void onDestroy() {
super.onDestroy();
LOG.logThis();
if (isAttrEditorShowing()) {
getAttrEditorSheet().dismiss();
@@ -315,8 +316,7 @@ public class DesignerActivity extends StudioActivity
} catch (Throwable e) {
LOG.error("Unable to release activity references from ILayoutInflater", e);
}
super.onDestroy();
mBinding = null;
}
private boolean isAttrEditorShowing() {
@@ -508,4 +508,5 @@ public class DesignerActivity extends StudioActivity
private void setDragDataToInflatedView(@NonNull IView view) {
view.setExtraData(new WidgetDragData(true, view, null));
}
}
@@ -933,7 +933,7 @@ public class EditorActivity extends StudioActivity
initialSetup();
setStatus(getString(R.string.msg_project_initialized));
mBinding.buildProgressIndicator.setVisibility(View.GONE);
if (mFindInProjectDialog != null && mFindInProjectDialog.isShowing()) {
mFindInProjectDialog.dismiss();
}
@@ -961,8 +961,8 @@ public class EditorActivity extends StudioActivity
@SuppressWarnings("UnusedReturnValue")
@NonNull
public CompletableFuture<TaskExecutionResult> execTasks(
Consumer<TaskExecutionResult> resultHandler, String... tasks) {
saveAll(false);
Consumer<TaskExecutionResult> resultHandler, String... tasks) {
saveAll(false);
runOnUiThread(() -> appendBuildOut("Executing tasks: " + TextUtils.join(", ", tasks)));
return mBuildService
.executeTasks(tasks)
@@ -1348,7 +1348,8 @@ public class EditorActivity extends StudioActivity
@Override
public void onTabSelected(TabLayout.Tab tab) {
final var fragment = bottomSheetTabAdapter.getFragmentAtIndex(tab.getPosition());
if (fragment instanceof NonEditableEditorFragment) {
if (fragment instanceof NonEditableEditorFragment
|| fragment instanceof LogViewFragment) {
mBinding.bottomSheet.clearFab.show();
mBinding.bottomSheet.shareOutputFab.show();
} else {
@@ -1376,6 +1377,11 @@ public class EditorActivity extends StudioActivity
if (editor.getEditor() != null) {
editor.getEditor().setText("");
}
} else if (fragment instanceof LogViewFragment) {
final var editor = (LogViewFragment) fragment;
if (editor.getEditor() != null) {
editor.getEditor().setText("");
}
}
});
@@ -1384,19 +1390,22 @@ public class EditorActivity extends StudioActivity
final var fragment =
bottomSheetTabAdapter.getFragmentAtIndex(
mBinding.bottomSheet.tabs.getSelectedTabPosition());
if (fragment instanceof NonEditableEditorFragment) {
final var editor = (NonEditableEditorFragment) fragment;
if (editor.getEditor() != null) {
final var text = editor.getEditor().getText();
final var type =
editor instanceof SimpleOutputFragment
? "build_output"
: editor instanceof IDELogFragment
? "ide_logs"
: editor instanceof LogViewFragment ? "app_logs" : "unknown_type";
shareText(text, type);
}
CharSequence text = "";
String type = "unknown_type";
if (fragment instanceof SimpleOutputFragment) {
var editor = (SimpleOutputFragment) fragment;
text = editor.getEditor().getText();
type = "build_output";
} else if (fragment instanceof IDELogFragment) {
var editor = (IDELogFragment) fragment;
text = editor.getEditor().getText();
type = "ide_logs";
} else if (fragment instanceof LogViewFragment) {
var editor = (IDELogFragment) fragment;
text = editor.getEditor().getText();
type = "app_logs";
}
shareText(text, type);
});
if (!getApp().getPrefManager().getBoolean(KEY_BOTTOM_SHEET_SHOWN)
@@ -1520,18 +1529,14 @@ public class EditorActivity extends StudioActivity
try {
//noinspection ConstantConditions
final var rootProject = ProjectManager.INSTANCE.getRootProject();
var projectName = rootProject.getName().get();
if(projectName.isEmpty())
{
projectName = new File(ProjectManager.INSTANCE.getProjectDirPath()).getName();
getSupportActionBar()
.setSubtitle(projectName);
}
else{
getSupportActionBar()
.setSubtitle(projectName);
}
var projectName = rootProject.getName().get();
if (projectName.isEmpty()) {
projectName = new File(ProjectManager.INSTANCE.getProjectDirPath()).getName();
getSupportActionBar().setSubtitle(projectName);
} else {
getSupportActionBar().setSubtitle(projectName);
}
} catch (Throwable th) {
// ignored
}
@@ -1575,7 +1580,7 @@ public class EditorActivity extends StudioActivity
}
initializeLanguageServers();
// Actually, we don't need to start FileOptionsHandler
// Because it would work anyway
// But still we do...
@@ -114,4 +114,10 @@ public class MainActivity extends StudioActivity {
getApp().toast(R.string.msg_storage_denied, Toaster.Type.ERROR);
finishAffinity();
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
}
}
@@ -65,4 +65,10 @@ public class PreferencesActivity extends StudioActivity {
public void onBackPressed() {
super.onBackPressed();
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
}
}
@@ -80,4 +80,10 @@ public class SplashActivity extends StudioActivity {
mHandler.postDelayed(mRunnable, 1000);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
}
}
@@ -217,6 +217,12 @@ public class TerminalActivity extends StudioActivity
setTerminalCursorBlinkingState(false);
}
@Override
protected void onDestroy() {
super.onDestroy();
binding = null;
}
public boolean isVisible() {
return isVisible;
}
@@ -22,32 +22,32 @@ import androidx.annotation.NonNull;
import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.utils.ILogger;
public class IDELogFragment extends LogViewFragment {
private final ILogger.LogListener listener = this::log;
public IDELogFragment() {
ILogger.addLogListener(listener);
}
@Override
protected String onCreateLogString(@NonNull LogLine line) {
return line.toSimpleString();
}
private void log(int priority, String tag, @NonNull String message) {
if (message.contains("\n")) {
final var split = message.split("\n");
for (var line : split) {
logLine(priority, tag, line);
}
} else {
logLine(priority, tag, message);
}
}
private void logLine(int priority, String tag, String message) {
final var line = new LogLine(ILogger.priorityChar(priority), tag, message);
appendLog(line);
}
}
public class IDELogFragment extends LogViewFragment {
private final ILogger.LogListener listener = this::log;
public IDELogFragment() {
ILogger.addLogListener(listener);
}
@Override
protected String onCreateLogString(@NonNull LogLine line) {
return line.toSimpleString();
}
private void log(int priority, String tag, @NonNull String message) {
if (message.contains("\n")) {
final var split = message.split("\n");
for (var line : split) {
logLine(priority, tag, line);
}
} else {
logLine(priority, tag, message);
}
}
private void logLine(int priority, String tag, String message) {
final var line = new LogLine(ILogger.priorityChar(priority), tag, message);
appendLog(line);
}
}
@@ -18,57 +18,147 @@
package com.itsaky.androidide.fragments;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.blankj.utilcode.util.StringUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.itsaky.androidide.R;
import com.itsaky.androidide.databinding.FragmentLogViewBinding;
import com.itsaky.androidide.language.logs.LogLanguageImpl;
import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
import com.itsaky.androidide.utils.TypefaceUtils;
import com.itsaky.androidide.views.editor.IDEEditor;
import com.itsaky.androidide.utils.SingleTextWatcher;
import io.github.rosemoe.sora.lang.Language;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import io.github.rosemoe.sora.lang.Language;
public class LogViewFragment extends Fragment {
public class LogViewFragment extends NonEditableEditorFragment {
private FragmentLogViewBinding binding;
private final Language language = getLanguage();
private final List<LogLine> unsavedLines = new ArrayList<>();
private char priority;
private String tag;
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentLogViewBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Objects.requireNonNull(getEditor()).setEditorLanguage(language);
final var editor = getEditor();
editor.setEditable(false);
editor.setDividerWidth(0);
editor.setWordwrap(false);
editor.setUndoEnabled(false);
editor.setTypefaceLineNumber(TypefaceUtils.jetbrainsMono());
editor.setTypefaceText(TypefaceUtils.jetbrainsMono());
editor.setTextSize(12);
editor.setColorScheme(new SchemeAndroidIDE());
editor.setEditorLanguage(language);
final var arr = requireContext().getResources().getStringArray(R.array.logcat_units);
binding.logPrioritySpinner.setAdapter(
new ArrayAdapter<>(
requireContext(),
androidx.appcompat.R.layout.support_simple_spinner_dropdown_item,
arr));
binding.logPrioritySpinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
priority = parent.getSelectedItem().toString().charAt(0);
getEditor().setText("");
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
binding
.tagFilterInput
.getEditText()
.addTextChangedListener(
new SingleTextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
tag = editable.toString();
getEditor().setText("");
}
});
if (!unsavedLines.isEmpty()) {
for (var line : unsavedLines) {
applyToLanguage(line);
getEditor().append(line.toString().trim() + "\n");
applyToLanguage(line);
}
unsavedLines.clear();
}
}
private boolean filterLog(char priority, String tag, LogLine l) {
return 'V' == priority
|| (l.priorityChar == priority)
&& (TextUtils.isEmpty(tag)
|| (!TextUtils.isEmpty(tag) && (l.tag.toLowerCase().contains(tag.toLowerCase()))));
}
private void applyToLanguage(LogLine line) {
if (language instanceof LogLanguageImpl) {
((LogLanguageImpl) this.language).addLine(line);
}
}
@Nullable
public IDEEditor getEditor() {
return binding.editor;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
public void appendLog(LogLine line) {
if (getEditor() == null) {
unsavedLines.add(line);
return;
if (filterLog(priority, tag, line)) {
if (getEditor() == null) {
unsavedLines.add(line);
return;
}
final var lineString = onCreateLogString(line);
final var msg = lineString.endsWith("\n") ? lineString : lineString + "\n";
ThreadUtils.runOnUiThread(() -> getEditor().append(msg));
applyToLanguage(line);
}
applyToLanguage(line);
final var lineString = onCreateLogString(line);
final var msg = lineString.endsWith("\n") ? lineString : lineString + "\n";
ThreadUtils.runOnUiThread(() -> getEditor().append(msg));
}
protected String onCreateLogString(@NonNull LogLine line) {
@@ -15,9 +15,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.transition.TransitionManager;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import com.google.android.material.transition.MaterialFadeThrough;
import com.google.android.material.transition.MaterialSharedAxis;
@@ -40,6 +39,7 @@ import com.itsaky.androidide.utils.AndroidUtils;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.FileUtil;
import com.itsaky.androidide.utils.SingleTextWatcher;
import com.itsaky.androidide.viewmodel.WizardViewModel;
import com.itsaky.toaster.Toaster;
import java.io.File;
@@ -47,8 +47,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
public class WizardFragment extends BaseFragment implements ProjectWriterCallback {
@@ -65,6 +63,8 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
private LayoutLoadingWizardBinding loadingLayout;
private SetupFooterBinding footerBinding;
private WizardViewModel mViewModel;
private ProgressSheet mProgressSheet;
private ProjectTemplate mCurrentTemplate;
private OnProjectCreatedListener mListener;
@@ -92,6 +92,7 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
templatesBinding = binding.wizardTemplatesLayout;
detailsBinding = binding.wizardDetailsLayout;
footerBinding = binding.footerLayout;
mViewModel = new ViewModelProvider(this).get(WizardViewModel.class);
return binding.getRoot();
}
@@ -106,14 +107,39 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
footerBinding.nextButton.setOnClickListener(v -> onNavigateNext());
footerBinding.exitButton.setOnClickListener(v -> onNavigateBack());
loadTemplates();
templatesBinding.templateRecyclerview.setLayoutManager(
new GridLayoutManager(requireContext(), 3));
mAdapter = new WizardTemplateAdapter();
templatesBinding.templateRecyclerview.setAdapter(mAdapter);
mViewModel.createTemplatesList();
mViewModel
.getProjects()
.observe(
getViewLifecycleOwner(),
(list) -> {
mAdapter.submitList(list);
});
mViewModel
.getLoadingState()
.observe(
getViewLifecycleOwner(),
(v) -> {
if (v) {
showLoading();
} else {
showTemplatesView();
}
});
mAdapter.setOnItemClickListener(
(item, pos) -> {
mCurrentTemplate = item;
onNavigateNext();
});
initDetailsView();
}
@@ -126,6 +152,7 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
@Override
public void onDestroyView() {
super.onDestroyView();
mViewModel = null;
binding = null;
loadingLayout = null;
templatesBinding = null;
@@ -139,87 +166,11 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
return view.getAdapter().getItem(pos).toString();
}
private void loadTemplates() {
private void showLoading() {
TransitionManager.beginDelayedTransition((ViewGroup) requireView(), new MaterialFadeThrough());
binding.loadingLayout.getRoot().setVisibility(View.VISIBLE);
binding.wizardTemplatesLayout.getRoot().setVisibility(View.GONE);
footerBinding.nextButton.setVisibility(View.GONE);
Executors.newSingleThreadExecutor()
.execute(
() -> {
List<ProjectTemplate> templates = createTemplates();
if (getActivity() != null) {
getActivity()
.runOnUiThread(
() -> {
TransitionManager.beginDelayedTransition(
(ViewGroup) requireView(), new MaterialFadeThrough());
binding.loadingLayout.getRoot().setVisibility(View.GONE);
binding.wizardTemplatesLayout.getRoot().setVisibility(View.VISIBLE);
mAdapter.submitList(templates);
mAdapter.setOnItemClickListener(
(item, pos) -> {
mCurrentTemplate = item;
onNavigateNext();
});
});
}
});
}
private List<ProjectTemplate> createTemplates() {
List<ProjectTemplate> mTemplates = new ArrayList<>();
ProjectTemplate
empty =
new ProjectTemplate()
.setId(0)
.setSupportJava(true)
.setSupportKotlin(true)
.setName(requireContext(), R.string.template_empty)
.setDescription(requireContext(), R.string.template_description_empty)
.setImageId(R.drawable.template_empty),
basic =
new ProjectTemplate()
.setId(1)
.setSupportJava(true)
.setSupportKotlin(true)
.setName(requireContext(), R.string.template_basic)
.setDescription(requireContext(), R.string.template_description_basic)
.setImageId(R.drawable.template_basic),
drawer =
new ProjectTemplate()
.setId(2)
.setSupportJava(true)
.setSupportKotlin(true)
.setName(requireContext(), R.string.template_navigation_drawer)
.setDescription(requireContext(), R.string.template_description_navigation_drawer)
.setImageId(R.drawable.template_navigation_drawer),
libgdx =
new ProjectTemplate()
.setId(3)
.setSupportJava(true)
.setName(requireContext(), R.string.template_libgdx)
.setDescription(requireContext(), R.string.template_description_libgdx)
.setImageId(R.drawable.template_libgdx),
compose =
new ProjectTemplate()
.setId(4)
.setSupportKotlin(true)
.setName(requireContext(), R.string.template_compose)
.setDescription(requireContext(), R.string.template_description_compose)
.setImageId(R.drawable.template_kotlin);
mTemplates.add(empty);
mTemplates.add(basic);
mTemplates.add(drawer);
mTemplates.add(libgdx);
mTemplates.add(compose);
return mTemplates;
}
private int getMinSdk() {
@@ -319,17 +270,18 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
}
private void showTemplatesView() {
templatesBinding.getRoot().setVisibility(View.GONE);
MaterialSharedAxis sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.X, false);
TransitionManager.beginDelayedTransition((ViewGroup) requireView(), sharedAxis);
binding.loadingLayout.getRoot().setVisibility(View.GONE);
templatesBinding.getRoot().setVisibility(View.GONE);
detailsBinding.getRoot().setVisibility(View.GONE);
templatesBinding.getRoot().setVisibility(View.VISIBLE);
footerBinding.nextButton.setVisibility(View.GONE);
footerBinding.nextButton.setText(R.string.next);
footerBinding.exitButton.setText(R.string.exit);
binding.wizardDescriptionId.setText(R.string.new_project);
}
private void showDetailsView() {
@@ -363,7 +315,9 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
detailsBinding.etLanguage.setListSelection(0);
detailsBinding.etLanguage.setText(getSelectedItem(0, detailsBinding.etLanguage), false);
minSdkIndex = manager.getInt(PREF_MIN_SDK_INDEX_KEY, 5);
targetSdkIndex = manager.getInt(PREF_TERGET_SDK_INDEX_KEY, 16);
// google recommended use latest target sdk version
targetSdkIndex = manager.getInt(PREF_TERGET_SDK_INDEX_KEY, getSdks().size() - 1);
detailsBinding.etMinSdk.setListSelection(minSdkIndex);
detailsBinding.etMinSdk.setText(getSelectedItem(minSdkIndex, detailsBinding.etMinSdk), false);
@@ -382,6 +336,7 @@ public class WizardFragment extends BaseFragment implements ProjectWriterCallbac
detailsBinding.getRoot().setVisibility(View.VISIBLE);
templatesBinding.getRoot().setVisibility(View.GONE);
binding.wizardDescriptionId.setText(mCurrentTemplate.getName());
footerBinding.nextButton.setText(R.string.create_project);
footerBinding.nextButton.setVisibility(View.VISIBLE);
footerBinding.exitButton.setText(R.string.previous);
@@ -1,56 +0,0 @@
package com.itsaky.androidide.utils;
import android.graphics.Color;
import android.util.Log;
import androidx.core.graphics.ColorUtils;
import com.itsaky.androidide.app.StudioApp;
import java.lang.reflect.Field;
public class ColorUtil {
public static boolean isDark(int color) {
return ColorUtils.calculateLuminance(color) < 0.25;
}
public static Object getAndroidColor(String clazz, String colorName) {
Field declaratedField;
try {
declaratedField = Class.forName(clazz).getField(colorName);
declaratedField.setAccessible(true);
return declaratedField.get(null);
} catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static int getColor(String colorValue) {
/*
if (colorValue.startsWith("@color/")) {
final var resTable = StudioApp.getInstance().getResourceTable();
String color = resTable.findColor(colorValue);
return getColor(color);
}
*/
if (colorValue.startsWith("@android:color/")) {
Object color = getAndroidColor("android.R$color", colorValue.substring(15));
if (color != null) {
return StudioApp.getInstance().getColor((Integer) color);
}
}
if (colorValue.startsWith("#")) {
return Color.parseColor(colorValue);
}
throw new NumberFormatException();
}
public static boolean isColorValue(String value) {
if (value.startsWith("#") | value.startsWith("@android:color") | value.startsWith("@color/")) {
return true;
}
return false;
}
}
@@ -0,0 +1,109 @@
package com.itsaky.androidide.viewmodel;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.blankj.utilcode.util.CollectionUtils;
import com.itsaky.androidide.R;
import com.itsaky.androidide.models.ProjectTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
public class WizardViewModel extends AndroidViewModel {
private MutableLiveData<List<ProjectTemplate>> mProjectTemplatesList =
new MutableLiveData<>(CollectionUtils.newArrayList());
private MutableLiveData<Boolean> mLoadingState = new MutableLiveData<>(true);
public WizardViewModel(@NonNull Application application) {
super(application);
}
public void createTemplatesList() {
Executors.newSingleThreadExecutor()
.execute(
() -> {
List<ProjectTemplate> mTemplates = new ArrayList<>();
ProjectTemplate
empty =
new ProjectTemplate()
.setId(0)
.setSupportJava(true)
.setSupportKotlin(true)
.setName(
getApplication().getApplicationContext(), R.string.template_empty)
.setDescription(
getApplication().getApplicationContext(),
R.string.template_description_empty)
.setImageId(R.drawable.template_empty),
basic =
new ProjectTemplate()
.setId(1)
.setSupportJava(true)
.setSupportKotlin(true)
.setName(
getApplication().getApplicationContext(), R.string.template_basic)
.setDescription(
getApplication().getApplicationContext(),
R.string.template_description_basic)
.setImageId(R.drawable.template_basic),
drawer =
new ProjectTemplate()
.setId(2)
.setSupportJava(true)
.setSupportKotlin(true)
.setName(
getApplication().getApplicationContext(),
R.string.template_navigation_drawer)
.setDescription(
getApplication().getApplicationContext(),
R.string.template_description_navigation_drawer)
.setImageId(R.drawable.template_navigation_drawer),
libgdx =
new ProjectTemplate()
.setId(3)
.setSupportJava(true)
.setName(
getApplication().getApplicationContext(), R.string.template_libgdx)
.setDescription(
getApplication().getApplicationContext(),
R.string.template_description_libgdx)
.setImageId(R.drawable.template_libgdx),
compose =
new ProjectTemplate()
.setId(4)
.setSupportKotlin(true)
.setName(
getApplication().getApplicationContext(), R.string.template_compose)
.setDescription(
getApplication().getApplicationContext(),
R.string.template_description_compose)
.setImageId(R.drawable.template_kotlin);
mTemplates.add(empty);
mTemplates.add(basic);
mTemplates.add(drawer);
mTemplates.add(libgdx);
mTemplates.add(compose);
mProjectTemplatesList.postValue(mTemplates);
mLoadingState.postValue(false);
});
}
public LiveData<List<ProjectTemplate>> getProjects() {
return mProjectTemplatesList;
}
public LiveData<Boolean> getLoadingState() {
return mLoadingState;
}
}
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp" >
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/log_priority_spinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:entries="@array/logcat_units" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tag_filter_input"
style="@style/AppTheme.TextInputLayout.Outlined"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:hint="@string/hint_log_tag_filter"
app:hintEnabled="true"
app:hintTextColor="@color/secondaryColor" >
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.itsaky.androidide.views.editor.IDEEditor
android:id="@+id/editor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
+14 -2
View File
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!--
<?xml version="1.0" encoding="utf-8"?>
<!--
~ This file is part of AndroidIDE.
~
~ AndroidIDE is free software: you can redistribute it and/or modify
@@ -13,8 +14,9 @@
~
~ You should have received a copy of the GNU General Public License
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
-->
-->
<resources>
<string-array name="dimension_units">
<item>dp</item>
<item>sp</item>
@@ -23,4 +25,14 @@
<item>in</item>
<item>mm</item>
</string-array>
<string-array name="logcat_units">
<item>Verbose</item>
<item>Debug</item>
<item>Info</item>
<item>Warning</item>
<item>Error</item>
<item>Fatal</item>
</string-array>
</resources>
+1
View File
@@ -380,6 +380,7 @@
<string name="wizard_loading">Templates loading...</string>
<string name="next">Next</string>
<string name="exit">Exit</string>
<string name="hint_log_tag_filter">Log tags filter</string>
<string name="idepref_title_tpFix">JDK 11 tag pointers fix</string>
<string name="idepref_msg_tpFix">Set LD_PRELOAD to libhook.so to fix tag pointers issue for JDK 11 in Android 11 [DEPRECATED - Prefer using JDK 17].</string>
@@ -1,179 +1,161 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*
*/
package com.itsaky.androidide.models;
public class LogLine {
// It makes things easier in LogLanguageImpl
public static int INFO;
public static int DEBUG;
public static int ERROR;
public static int WARNING;
static {
try {
final var klass = Class.forName("com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE");
INFO = klass.getField("LOG_INFO").getInt(null);
DEBUG = klass.getField("LOG_DEBUG").getInt(null);
ERROR = klass.getField("LOG_ERROR").getInt(null);
WARNING = klass.getField("LOG_WARNING").getInt(null);
} catch (Throwable err) {
INFO = 0;
DEBUG = 1;
ERROR = 2;
WARNING = 3;
}
}
public String unformatted;
public String date;
public String time;
public String pid;
public String tid;
public String tag;
public String message;
public char priorityChar;
public int priority;
public boolean formatted;
// For JSONRpc
@SuppressWarnings("unused")
private LogLine() {}
public LogLine(char priorityChar, String tag, String message) {
this("", "", "", "", priorityChar, tag, message);
}
public LogLine(
String date,
String time,
String pid,
String tid,
char priorityChar,
String tag,
String message) {
this(date, time, pid, tid, priorityChar, tag, message, true);
}
public LogLine(
String date,
String time,
String pid,
String tid,
char priorityChar,
String tag,
String message,
boolean formatted) {
this.date = date;
this.time = time;
this.pid = pid;
this.tid = tid;
this.priorityChar = priorityChar;
this.tag = tag;
this.message = message;
this.priority = parsePriority(priorityChar);
this.formatted = formatted;
if (tag.length() > 25) {
this.tag = "...".concat(tag.substring(tag.length() - 25));
}
}
private int parsePriority(char s) {
final var c = Character.toLowerCase(s);
if (c == 'w') {
return WARNING;
} else if (c == 'e') {
return ERROR;
} else if (c == 'i') {
return INFO;
} else {
return DEBUG;
}
}
public LogLine(String unformatted) {
this.unformatted = unformatted;
this.formatted = false;
}
public static LogLine forLogString(final String log) {
try {
final var split = log.split("\\s", 7);
return new LogLine(
split[0], // date
split[1], // time
split[2], // process id
split[3], // thread id
split[4].charAt(0), // priority
split[5], // tag
split[6] // message
);
} catch (Throwable th) {
return new LogLine(log);
}
}
public int getColor() {
int id = 0xffffffff;
if (priority == WARNING) {
id = 0xffff7043;
} else if (priority == ERROR) {
id = 0xffc50e29;
} else if (priority == INFO) {
id = 0xff4caf50;
}
return id;
}
@Override
public String toString() {
return this.formatted
? String.format(
"%-6s %-13s %-6s %-6s %-2s %-35s %s",
date, time, pid, tid, priorityChar, trimIfNeeded(tag, 35), message)
: this.unformatted;
}
private String trimIfNeeded(String tag, int maxLength) {
final var sb = new StringBuilder(tag);
final var length = tag.length();
if (length > maxLength) {
final var start = length - maxLength;
sb.delete(0, start);
// When the tag is long enough, prefix the tag with '..'
sb.setCharAt(0, '.');
sb.setCharAt(1, '.');
}
return sb.toString();
}
public String toSimpleString() {
return this.formatted
? String.format("%-25s %-2s %s", trimIfNeeded(tag, 25), priorityChar, message)
: this.unformatted;
}
public String formattedTagAndMessage() {
return this.formatted
? String.format("%-25s %s", trimIfNeeded(tag, 25), message)
: this.unformatted;
}
}
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*
*/
package com.itsaky.androidide.models;
public class LogLine {
// It makes things easier in LogLanguageImpl
public static int INFO;
public static int DEBUG;
public static int ERROR;
public static int WARNING;
static {
try {
final var klass = Class.forName("com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE");
INFO = klass.getField("LOG_INFO").getInt(null);
DEBUG = klass.getField("LOG_DEBUG").getInt(null);
ERROR = klass.getField("LOG_ERROR").getInt(null);
WARNING = klass.getField("LOG_WARNING").getInt(null);
} catch (Throwable err) {
INFO = 0;
DEBUG = 1;
ERROR = 2;
WARNING = 3;
}
}
public String unformatted;
public String date;
public String time;
public String pid;
public String tid;
public String tag;
public String message;
public char priorityChar;
public int priority;
public boolean formatted;
// For JSONRpc
@SuppressWarnings("unused")
private LogLine() {}
public LogLine(char priorityChar, String tag, String message) {
this("", "", "", "", priorityChar, tag, message);
}
public LogLine(
String date,
String time,
String pid,
String tid,
char priorityChar,
String tag,
String message) {
this(date, time, pid, tid, priorityChar, tag, message, true);
}
public LogLine(
String date,
String time,
String pid,
String tid,
char priorityChar,
String tag,
String message,
boolean formatted) {
this.date = date;
this.time = time;
this.pid = pid;
this.tid = tid;
this.priorityChar = priorityChar;
this.tag = tag;
this.message = message;
this.priority = parsePriority(priorityChar);
this.formatted = formatted;
}
private int parsePriority(char s) {
final var c = Character.toLowerCase(s);
if (c == 'w') {
return WARNING;
} else if (c == 'e') {
return ERROR;
} else if (c == 'i') {
return INFO;
} else {
return DEBUG;
}
}
public LogLine(String unformatted) {
this.unformatted = unformatted;
this.formatted = false;
}
public static LogLine forLogString(final String log) {
try {
final var split = log.split("\\s", 7);
return new LogLine(
split[0], // date
split[1], // time
split[2], // process id
split[3], // thread id
split[4].charAt(0), // priority
split[5], // tag
split[6] // message
);
} catch (Throwable th) {
return new LogLine(log);
}
}
@Override
public String toString() {
return this.formatted
? String.format("%s %s %s/%s %s/%s %s", date, time, pid, tid, priorityChar, tag, message)
: this.unformatted;
}
private String trimIfNeeded(String tag, int maxLength) {
final var sb = new StringBuilder(tag);
final var length = tag.length();
if (length > maxLength) {
final var start = length - maxLength;
sb.delete(0, start);
// When the tag is long enough, prefix the tag with '..'
sb.setCharAt(0, '.');
sb.setCharAt(1, '.');
}
return sb.toString();
}
public String toSimpleString() {
return this.formatted
? String.format("%-25s %-2s %s", trimIfNeeded(tag, 25), priorityChar, message)
: this.unformatted;
}
public String formattedTagAndMessage() {
return this.formatted
? String.format("%-25s %s", trimIfNeeded(tag, 25), message)
: this.unformatted;
}
}