diff --git a/app/build.gradle b/app/build.gradle
index 7bacca8a6..3b3787e55 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -74,6 +74,7 @@ dependencies {
// TODO: completion providers should not be included on the main module
// alternate editor impl
implementation 'com.blacksquircle.ui:editorkit:2.1.2'
+ implementation 'com.caverock:androidsvg-aar:1.4'
implementation project(path: ':code-editor')
implementation project(path: ':xml-completion')
diff --git a/app/src/main/assets/Icons.zip b/app/src/main/assets/Icons.zip
new file mode 100644
index 000000000..e262ca52d
Binary files /dev/null and b/app/src/main/assets/Icons.zip differ
diff --git a/app/src/main/java/com/tyron/code/ApplicationLoader.java b/app/src/main/java/com/tyron/code/ApplicationLoader.java
index 8c2d380cd..410f333cb 100644
--- a/app/src/main/java/com/tyron/code/ApplicationLoader.java
+++ b/app/src/main/java/com/tyron/code/ApplicationLoader.java
@@ -27,6 +27,7 @@
import com.tyron.code.ui.main.action.debug.DebugActionGroup;
import com.tyron.code.ui.main.action.other.FormatAction;
import com.tyron.code.ui.main.action.other.OpenSettingsAction;
+import com.tyron.code.ui.main.action.other.OpenIconManagerAction;
import com.tyron.code.ui.main.action.project.ProjectActionGroup;
import com.tyron.code.ui.settings.ApplicationSettingsFragment;
import com.tyron.common.ApplicationProvider;
@@ -145,6 +146,7 @@ private void runStartup() {
manager.registerAction(CompileActionGroup.ID, new CompileActionGroup());
manager.registerAction(ProjectActionGroup.ID, new ProjectActionGroup());
manager.registerAction(PreviewLayoutAction.ID, new PreviewLayoutAction());
+ manager.registerAction(OpenIconManagerAction.ID, new OpenIconManagerAction());
manager.registerAction(OpenSettingsAction.ID, new OpenSettingsAction());
manager.registerAction(FormatAction.ID, new FormatAction());
manager.registerAction(DebugActionGroup.ID, new DebugActionGroup());
@@ -190,4 +192,4 @@ public static void showToast(String message) {
public static void setApplicationContext(Context context) {
applicationContext = context;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/tyron/code/ui/iconmanager/EditVectorDialogFragment.java b/app/src/main/java/com/tyron/code/ui/iconmanager/EditVectorDialogFragment.java
new file mode 100644
index 000000000..b7bc42a22
--- /dev/null
+++ b/app/src/main/java/com/tyron/code/ui/iconmanager/EditVectorDialogFragment.java
@@ -0,0 +1,197 @@
+package com.tyron.code.ui.iconmanager;
+
+import android.graphics.PorterDuff;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PictureDrawable;
+
+import android.text.Editable;
+import android.view.View;
+import android.os.Bundle;
+import android.app.Dialog;
+
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import com.caverock.androidsvg.SVG;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import androidx.fragment.app.DialogFragment;
+import com.google.android.material.textfield.TextInputEditText;
+import com.google.android.material.textfield.TextInputLayout;
+
+import com.tyron.code.R;
+import com.tyron.code.ui.project.ProjectManager;
+import com.tyron.common.util.SingleTextWatcher;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Document;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+public class EditVectorDialogFragment extends DialogFragment {
+
+ public static final String TAG = EditVectorDialogFragment.class.getSimpleName();
+ public static final String ADD_KEY = "addVector";
+ private String iconPath, projectResourceDirectory;
+
+ @SuppressWarnings("ConstantConditions")
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+
+ Bundle bundle = this.getArguments();
+ if (bundle != null) {
+ iconPath = bundle.getString("iconPath");
+ projectResourceDirectory = ProjectManager.getInstance().getCurrentProject().getRootFile().getAbsolutePath() + "/app/src/main/res/drawable/";
+ }
+
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext());
+ View inflate = getLayoutInflater().inflate(R.layout.create_vector_dialog, null);
+ TextInputLayout textinput1 = (TextInputLayout) inflate.findViewById(R.id.textinputlayout1);
+ TextInputLayout textinput2 = (TextInputLayout) inflate.findViewById(R.id.textinputlayout2);
+ TextInputLayout textinput3 = (TextInputLayout) inflate.findViewById(R.id.textinputlayout3);
+ TextInputLayout textinput4 = (TextInputLayout) inflate.findViewById(R.id.textinputlayout4);
+ TextInputLayout textinput5 = (TextInputLayout) inflate.findViewById(R.id.textinputlayout5);
+ TextInputEditText name = (TextInputEditText) inflate.findViewById(R.id.name);
+ TextInputEditText height = (TextInputEditText) inflate.findViewById(R.id.height);
+ TextInputEditText width = (TextInputEditText) inflate.findViewById(R.id.width);
+ TextInputEditText color = (TextInputEditText) inflate.findViewById(R.id.color);
+ TextInputEditText path = (TextInputEditText) inflate.findViewById(R.id.path);
+ ImageView icon = (ImageView) inflate.findViewById(R.id.icon);
+ LinearLayout container = (LinearLayout) inflate.findViewById(R.id.container);
+ LinearLayout round = (LinearLayout) inflate.findViewById(R.id.round);
+
+ round.setBackgroundColor(0XFF000000);
+ path.setEnabled(false);
+ path.setText(projectResourceDirectory);
+
+ textinput4.setEndIconOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (!color.getText().toString().trim().startsWith("#")) {
+ Toast.makeText(requireContext(), "Invalid color code", 3000).show();
+ } else {
+ try {
+ icon.setColorFilter(Color.parseColor(color.getText().toString().trim()), PorterDuff.Mode.MULTIPLY);
+ round.setBackgroundColor(Color.parseColor(color.getText().toString().trim()));
+ } catch (Exception e) {
+ Toast.makeText(requireContext(), e.toString(), 3000).show();
+ }
+ }
+ }
+ });
+
+ builder.setView(inflate);
+
+ if (iconPath.contains(".svg")) {
+ name.setText(new File(iconPath).getName().replace(".svg", ""));
+ } else if (iconPath.contains(".xml")) {
+ name.setText(new File(iconPath).getName().replace(".xml", ""));
+ }
+
+ icon.setImageDrawable(loadSvg(iconPath));
+
+ builder.setPositiveButton("Create", (d, w) -> {
+ generateSvg2Vector(name.getText().toString().trim(), width.getText().toString().trim(), height.getText().toString().trim(), color.getText().toString().trim(), iconPath, projectResourceDirectory);
+ });
+
+ builder.setNegativeButton("Cancel", null);
+
+ AlertDialog dialog = builder.create();
+ dialog.setOnShowListener(d -> {
+ final Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ SingleTextWatcher textWatcher = new SingleTextWatcher() {
+ @Override
+ public void afterTextChanged(Editable editable) {
+ boolean valid = validate(name, height, width, color, path);
+ positiveButton.setEnabled(valid);
+ }
+ };
+
+ name.addTextChangedListener(textWatcher);
+ height.addTextChangedListener(textWatcher);
+ width.addTextChangedListener(textWatcher);
+ color.addTextChangedListener(textWatcher);
+ path.addTextChangedListener(textWatcher);
+ });
+
+ return dialog;
+ }
+
+ private void generateSvg2Vector(String name, String width, String height, String color, String source, String destination) {
+
+ File svgPath = new File(source);
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+ try {
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.parse(svgPath);
+ NodeList nodeList = document.getElementsByTagName("path");
+ if (nodeList.getLength() > 0) {
+ Element element = (Element) nodeList.item(0);
+ String a = "\n \n\n";
+
+ byte[] vectorText = a.getBytes(StandardCharsets.UTF_8);
+
+ Files.write(Paths.get(new File(projectResourceDirectory + name + ".xml").toURI()), vectorText, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+
+ }
+ } catch (Exception e) {
+ Toast.makeText(requireContext(), e.toString(), 3000).show();
+ }
+ }
+
+ private boolean validate(EditText name, EditText height, EditText width, EditText color, EditText path) {
+ if (name.getText().toString().trim().isEmpty() && name.getText().toString().trim().endsWith(".xml") && name.getText().toString().endsWith(".svg")) {
+ return false;
+ } else if (height.getText().toString().trim().isEmpty()) {
+ return false;
+ } else if (width.getText().toString().trim().isEmpty()) {
+ return false;
+ } else if (color.getText().toString().trim().isEmpty()) {
+ return false;
+ } else if (path.getText().toString().trim().isEmpty()) {
+ return false;
+ }
+ return !name.getText().toString().contains(".xml") && !name.getText().toString().contains(".svg");
+ }
+
+ private Drawable loadSvg(String path) {
+ Drawable drawable = null;
+ try {
+ FileInputStream fileInputStream = new FileInputStream(new File(path));
+ SVG svg = SVG.getFromInputStream(fileInputStream);
+ drawable = new PictureDrawable(svg.renderToPicture());
+ } catch (Exception e) {
+ Toast.makeText(requireContext(), e.toString(), 3000).show();
+ }
+ return drawable;
+ }
+}
diff --git a/app/src/main/java/com/tyron/code/ui/iconmanager/IconManagerFragment.java b/app/src/main/java/com/tyron/code/ui/iconmanager/IconManagerFragment.java
new file mode 100644
index 000000000..8601f05db
--- /dev/null
+++ b/app/src/main/java/com/tyron/code/ui/iconmanager/IconManagerFragment.java
@@ -0,0 +1,146 @@
+package com.tyron.code.ui.iconmanager;
+
+import android.app.ProgressDialog;
+import android.os.Bundle;
+
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.appcompat.widget.Toolbar;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import com.google.android.material.transition.MaterialSharedAxis;
+
+import com.tyron.code.R;
+import com.tyron.code.util.UiUtilsKt;
+import com.tyron.code.ui.project.ProjectManager;
+import com.tyron.completion.progress.ProgressManager;
+import com.tyron.common.util.Decompress;
+import com.tyron.code.ui.iconmanager.adapter.IconAdapter;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.ArrayList;
+import org.w3c.dom.Document;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
+
+public class IconManagerFragment extends Fragment {
+
+ public static String TAG = IconManagerFragment.class.getSimpleName();
+ private String iconFolderDirectory, projectResourceDirectory;
+ private ArrayList iconList = new ArrayList<>();
+ private ProgressDialog pDialog;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.X, true));
+ setExitTransition(new MaterialSharedAxis(MaterialSharedAxis.X, false));
+
+ iconFolderDirectory = getPackageDirectory() + "/Icons/";
+ }
+
+ @Nullable
+
+ @Override
+
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+
+ View view = inflater.inflate(R.layout.icon_manager_fragment, container, false);
+
+ pDialog = new ProgressDialog(requireContext());
+ RecyclerView recyclerView = view.findViewById(R.id.recyclerview);
+ Toolbar toolbar = view.findViewById(R.id.toolbar);
+ UiUtilsKt.addSystemWindowInsetToPadding(toolbar, false, true, false, false);
+ if (!new File(getPackageDirectory() + "/Icons/").exists()) {
+ showConfirmationDialog(recyclerView, pDialog);
+ } else {
+ loadIcons(iconFolderDirectory, iconList, recyclerView);
+ }
+
+ return view;
+ }
+
+ @Override
+
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+
+ }
+
+ private void showConfirmationDialog(RecyclerView recyclerView, final ProgressDialog progressDialog) {
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext());
+ builder.setTitle("Warning!");
+ builder.setMessage("Do you want to extract all icons from CodeAssist?");
+ builder.setPositiveButton("EXTRACT", (d, w) -> {
+ progressDialog.setMessage("Extracting icons");
+ progressDialog.setCancelable(false);
+ progressDialog.show();
+ ProgressManager.getInstance().runNonCancelableAsync(() ->startExtractingIcons(progressDialog, recyclerView));
+ });
+ builder.setNegativeButton("CANCEL", null);
+ builder.create().show();
+ }
+
+ private void startExtractingIcons(final ProgressDialog progressDialog, RecyclerView recyclerView) {
+ Decompress.unzipFromAssets(requireContext(), "Icons.zip", getPackageDirectory());
+
+ ProgressManager.getInstance().runLater(() -> {
+ if (progressDialog.isShowing()) {
+ progressDialog.dismiss();
+ Toast.makeText(requireContext(), "Please restart Icon manager", 3000).show();
+ }
+ });
+ }
+
+ private void loadIcons(String path, ArrayList list, RecyclerView recyclerView) {
+ list.clear();
+ getFileList(path, list);
+ recyclerView.setNestedScrollingEnabled(false);
+ recyclerView.setAdapter(new IconAdapter(list, requireContext()));
+ recyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 4));
+ }
+
+ private String getPackageDirectory() {
+ return requireContext().getExternalFilesDir(null).getAbsolutePath();
+ }
+
+ public static void makeDirs(String path) {
+ if (!new File(path).exists()) {
+ new File(path).mkdirs();
+ }
+ }
+
+ public static void getFileList(String source, ArrayList list) {
+ File dir = new File(source);
+ if (!dir.exists() || dir.isFile())
+ return;
+ File[] listFiles = dir.listFiles();
+ if (listFiles == null || listFiles.length <= 0)
+ return;
+ if (list == null)
+ return;
+ list.clear();
+ for (File file : listFiles) {
+ list.add(file.getAbsolutePath());
+ }
+ }
+}
diff --git a/app/src/main/java/com/tyron/code/ui/iconmanager/adapter/IconAdapter.java b/app/src/main/java/com/tyron/code/ui/iconmanager/adapter/IconAdapter.java
new file mode 100644
index 000000000..f98513915
--- /dev/null
+++ b/app/src/main/java/com/tyron/code/ui/iconmanager/adapter/IconAdapter.java
@@ -0,0 +1,235 @@
+package com.tyron.code.ui.iconmanager.adapter;
+
+import android.content.Context;
+
+import android.graphics.Bitmap;
+
+import android.graphics.BitmapFactory;
+
+import android.graphics.PorterDuff;
+
+import android.graphics.drawable.Drawable;
+
+import android.graphics.drawable.PictureDrawable;
+
+import android.net.Uri;
+
+import android.os.Bundle;
+
+import android.view.LayoutInflater;
+
+import android.view.View;
+
+import android.view.ViewGroup;
+
+import android.widget.ImageView;
+
+import android.widget.LinearLayout;
+
+import android.widget.TextView;
+
+import android.widget.Toast;
+
+import androidx.fragment.app.Fragment;
+
+import androidx.fragment.app.FragmentActivity;
+
+import androidx.fragment.app.FragmentManager;
+
+import com.caverock.androidsvg.SVG;
+
+import com.caverock.androidsvg.SVGParseException;
+
+import com.tyron.code.ui.iconmanager.EditVectorDialogFragment;
+
+import com.tyron.code.ui.iconmanager.IconManagerFragment;
+
+import com.tyron.code.R;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.io.ByteArrayInputStream;
+
+import java.io.File;
+
+import java.io.FileNotFoundException;
+
+import java.io.FileInputStream;
+
+import java.io.InputStream;
+
+import java.nio.charset.StandardCharsets;
+
+import java.util.ArrayList;
+
+import java.util.HashMap;
+
+public class IconAdapter extends RecyclerView.Adapter {
+
+ private ArrayList data; private Context c;
+
+ private LinearLayout base;
+
+ private ImageView icon;
+
+ private TextView name;
+
+ public IconAdapter(ArrayList arr, Context context) {
+
+ data = arr;
+
+ c = context;
+
+ }
+
+ @Override
+
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+
+ View v = LayoutInflater.from(c).inflate(R.layout.icon_manager_item, null);
+
+ RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ v.setLayoutParams(lp);
+
+ return new ViewHolder(v);
+
+ }
+
+ @Override
+
+ public void onBindViewHolder(ViewHolder holder, final int position) {
+
+ View view = holder.itemView;
+
+ base = view.findViewById(R.id.linear1);
+
+ icon = view.findViewById(R.id.imageview1);
+
+ name = view.findViewById(R.id.textview1);
+
+ if (!data.get(position).isEmpty()) {
+
+ if (new File(data.get(position)).getName().endsWith(".svg")) {
+
+ name.setText(new File(data.get(position)).getName().replace(".svg", ""));
+
+ } else if (new File(data.get(position)).getName().endsWith(".xml")) {
+
+ name.setText(new File(data.get(position)).getName().replace(".xml", ""));
+
+ }
+
+ }
+
+ if (isFile(data.get(position))) {
+
+ if (data.get(position).contains(".svg") || data.get(position).contains(".xml")) {
+
+ try {
+
+ icon.setImageDrawable(loadSvg(data.get(position)));
+
+ } catch (Exception e) {
+
+ Toast.makeText(c, e.toString(), 3000).show();
+
+ }
+
+ }
+
+ }
+
+ icon.setColorFilter(0xFF000000, PorterDuff.Mode.MULTIPLY);
+
+ name.setSelected(true);
+
+ base.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+
+ public void onClick(View view) {
+
+ Bundle bundle = new Bundle();
+
+ bundle.putString("iconPath", data.get(position));
+
+ bundle.putInt("position", position);
+
+ FragmentActivity activity = (FragmentActivity) (c);
+
+ FragmentManager fm = activity.getSupportFragmentManager();
+
+ if (fm.findFragmentByTag(EditVectorDialogFragment.TAG) == null) {
+
+ EditVectorDialogFragment fragment = new EditVectorDialogFragment();
+
+ fragment.setArguments(bundle);
+
+ fragment.show(fm, EditVectorDialogFragment.TAG);
+
+ }
+
+ }
+
+ });
+
+ }
+
+ @Override
+
+ public int getItemCount() {
+
+ return data.size();
+
+ }
+
+ public boolean isFile(String path) {
+
+ if (!new File(path).exists())
+
+ return false;
+
+ return new File(path).isFile();
+
+ }
+
+ public Drawable loadSvg(String path) {
+
+ Drawable drawable = null;
+
+ try {
+
+ FileInputStream fileInputStream = new FileInputStream(new File(path));
+
+ try {
+
+ SVG svg = SVG.getFromInputStream(fileInputStream);
+
+ drawable = new PictureDrawable(svg.renderToPicture());
+
+ } catch (SVGParseException e) {
+
+ }
+
+ } catch (FileNotFoundException e) {
+
+ }
+
+ return drawable;
+
+ }
+
+ public class ViewHolder extends RecyclerView.ViewHolder {
+
+ public ViewHolder(View v) {
+
+ super(v);
+
+ }
+
+ }
+
+}
diff --git a/app/src/main/java/com/tyron/code/ui/main/action/other/OpenIconManagerAction.java b/app/src/main/java/com/tyron/code/ui/main/action/other/OpenIconManagerAction.java
new file mode 100644
index 000000000..d22fa14cd
--- /dev/null
+++ b/app/src/main/java/com/tyron/code/ui/main/action/other/OpenIconManagerAction.java
@@ -0,0 +1,136 @@
+package com.tyron.code.ui.main.action.other;
+
+import android.app.Activity;
+
+import android.content.Context;
+
+import android.content.ContextWrapper;
+
+import android.view.ContextThemeWrapper;
+
+import androidx.annotation.NonNull;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import androidx.fragment.app.Fragment;
+
+import androidx.fragment.app.FragmentManager;
+
+import com.tyron.actions.ActionPlaces;
+
+import com.tyron.actions.AnAction;
+
+import com.tyron.actions.AnActionEvent;
+
+import com.tyron.actions.CommonDataKeys;
+
+import com.tyron.actions.Presentation;
+
+import com.tyron.builder.project.Project;
+
+import com.tyron.builder.project.api.Module;
+
+import com.tyron.code.R;
+
+import com.tyron.code.ui.iconmanager.IconManagerFragment;
+
+public class OpenIconManagerAction extends AnAction {
+
+ public static final String ID = "openIconManagerAction";
+
+@Override
+
+ public void update(@NonNull AnActionEvent event) {
+
+ Presentation presentation = event.getPresentation();
+
+ Context context = event.getDataContext();
+
+ presentation.setVisible(false);
+
+ if (!ActionPlaces.MAIN_TOOLBAR.equals(event.getPlace())) {
+
+ return;
+
+ }
+
+ Project project = event.getData(CommonDataKeys.PROJECT);
+
+ if (project == null) {
+
+ return;
+
+ }
+
+ presentation.setText(context.getString(R.string.menu_icon_manager));
+
+ presentation.setVisible(true);
+
+ presentation.setEnabled(true);
+
+ }
+
+ @Override
+
+ public void actionPerformed(@NonNull AnActionEvent e) {
+
+ Context context = e.getRequiredData(CommonDataKeys.CONTEXT);
+
+ context = getActivityContext(context);
+
+ Project project = e.getRequiredData(CommonDataKeys.PROJECT);
+
+ Module mainModule = project.getMainModule();
+
+ if (context instanceof AppCompatActivity) {
+
+ FragmentManager fragmentManager =
+
+ ((AppCompatActivity) context).getSupportFragmentManager();
+
+ Fragment fragment = new IconManagerFragment();
+
+ fragmentManager.beginTransaction()
+
+ .replace(R.id.fragment_container, fragment, IconManagerFragment.TAG)
+
+ .addToBackStack(IconManagerFragment.TAG)
+
+ .commit();
+
+ }
+
+ }
+
+
+
+ private Context getActivityContext(Context context) {
+
+ Context current = context;
+
+ while (current != null) {
+
+ if (current instanceof Activity) {
+
+ return current;
+
+ }
+
+ if (current instanceof ContextWrapper) {
+
+ current = ((ContextWrapper) current).getBaseContext();
+
+ } else {
+
+ current = null;
+
+ }
+
+ }
+
+ return null;
+
+ }
+
+}
+
diff --git a/app/src/main/res/drawable/outline_sync_24.xml b/app/src/main/res/drawable/outline_sync_24.xml
new file mode 100644
index 000000000..74598aca2
--- /dev/null
+++ b/app/src/main/res/drawable/outline_sync_24.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/create_vector_dialog.xml b/app/src/main/res/layout/create_vector_dialog.xml
new file mode 100644
index 000000000..b3a61b74b
--- /dev/null
+++ b/app/src/main/res/layout/create_vector_dialog.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/icon_manager_fragment.xml b/app/src/main/res/layout/icon_manager_fragment.xml
new file mode 100644
index 000000000..f0d234338
--- /dev/null
+++ b/app/src/main/res/layout/icon_manager_fragment.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/icon_manager_item.xml b/app/src/main/res/layout/icon_manager_item.xml
new file mode 100644
index 000000000..fc709cf42
--- /dev/null
+++ b/app/src/main/res/layout/icon_manager_item.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/code_editor_menu.xml b/app/src/main/res/menu/code_editor_menu.xml
index 91b6fd1cb..cb33bc3fa 100644
--- a/app/src/main/res/menu/code_editor_menu.xml
+++ b/app/src/main/res/menu/code_editor_menu.xml
@@ -45,6 +45,10 @@
+
+
- Library manager
Format
Settings
+ Icon Manager
Application