diff --git a/app/src/main/java/org/mian/gitnex/activities/CodeEditorActivity.java b/app/src/main/java/org/mian/gitnex/activities/CodeEditorActivity.java index 2f902e97..310de346 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CodeEditorActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CodeEditorActivity.java @@ -1,10 +1,13 @@ package org.mian.gitnex.activities; +import android.app.Activity; +import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; import android.os.Bundle; import android.widget.ArrayAdapter; import com.amrdeveloper.codeview.Code; +import org.apache.commons.lang3.EnumUtils; import org.mian.gitnex.R; import org.mian.gitnex.databinding.ActivityCodeEditorBinding; import org.mian.gitnex.helpers.codeeditor.CustomCodeViewAdapter; @@ -25,7 +28,7 @@ public class CodeEditorActivity extends BaseActivity { private ActivityCodeEditorBinding binding; private LanguageManager languageManager; - private final LanguageName currentLanguage = LanguageName.JAVA; + private LanguageName currentLanguage = LanguageName.UNKNOWN; private final ThemeName currentTheme = ThemeName.FIVE_COLOR; @Override @@ -34,13 +37,36 @@ public class CodeEditorActivity extends BaseActivity { binding = ActivityCodeEditorBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - binding.close.setOnClickListener(view -> finish()); + binding.close.setOnClickListener(view -> { + sendResults(); + finish(); + }); - configCodeView(currentLanguage); + String fileContent = getIntent().getStringExtra("fileContent"); + String fileExtension; + + if(getIntent().getStringExtra("fileExtension") != null) { + fileExtension = getIntent().getStringExtra("fileExtension").toUpperCase(); + + if(EnumUtils.isValidEnum(LanguageName.class, fileExtension)) { + currentLanguage = LanguageName.valueOf(fileExtension); + } + else { + currentLanguage = LanguageName.UNKNOWN; + } + } + + configCodeView(currentLanguage, fileContent); configCodeViewPlugins(); } - private void configCodeView(LanguageName currentLanguage) { + private void sendResults() { + Intent intent = new Intent(); + intent.putExtra("fileContentFromActivity", binding.codeView.getText().toString()); + setResult(Activity.RESULT_OK, intent); + } + + private void configCodeView(LanguageName currentLanguage, String fileContent) { binding.codeView.setTypeface(Typeface.createFromAsset(ctx.getAssets(), "fonts/sourcecodeproregular.ttf")); @@ -69,6 +95,7 @@ public class CodeEditorActivity extends BaseActivity { binding.codeView.setPairCompleteMap(pairCompleteMap); binding.codeView.enablePairComplete(true); binding.codeView.enablePairCompleteCenterCursor(true); + binding.codeView.setText(fileContent); // Setup the auto complete and auto indenting for the current language configLanguageAutoComplete(); diff --git a/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java index 72719488..7b9ba9d6 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java @@ -1,6 +1,7 @@ package org.mian.gitnex.activities; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -10,7 +11,10 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.ArrayAdapter; import android.widget.TextView; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; +import org.apache.commons.io.FilenameUtils; import org.gitnex.tea4j.v2.models.Branch; import org.gitnex.tea4j.v2.models.CreateFileOptions; import org.gitnex.tea4j.v2.models.DeleteFileOptions; @@ -27,6 +31,7 @@ import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.contexts.RepositoryContext; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import retrofit2.Call; import retrofit2.Callback; @@ -97,7 +102,6 @@ public class CreateFileActivity extends BaseActivity { binding.newFileNameLayout.setVisibility(View.GONE); binding.newFileContentLayout.setVisibility(View.GONE); - } if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", FILE_ACTION_EDIT) == FILE_ACTION_EDIT) { @@ -114,20 +118,38 @@ public class CreateFileActivity extends BaseActivity { binding.newFileName.setFocusable(false); binding.newFileContent.setText(getIntent().getStringExtra("fileContents")); - } getBranches(repository.getOwner(), repository.getName()); disableProcessButton(); + binding.openCodeEditor.setOnClickListener(v -> + launchCodeEditorActivityForResult(Objects.requireNonNull(binding.newFileContent.getText()).toString(), FilenameUtils.getExtension(String.valueOf(binding.newFileName.getText()))) + ); + NetworkStatusObserver networkStatusObserver = NetworkStatusObserver.getInstance(ctx); networkStatusObserver.registerNetworkStatusListener(hasNetworkConnection -> runOnUiThread(() -> binding.newFileCreate.setEnabled(hasNetworkConnection))); binding.newFileCreate.setOnClickListener(v -> processNewFile()); - } + public void launchCodeEditorActivityForResult(String fileContent, String fileExtension) { + Intent intent = new Intent(this, CodeEditorActivity.class); + intent.putExtra("fileExtension", fileExtension); + intent.putExtra("fileContent", fileContent); + codeEditorActivityResultLauncher.launch(intent); + } + + ActivityResultLauncher codeEditorActivityResultLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), result -> { + if(result.getResultCode() == Activity.RESULT_OK) { + Intent data = result.getData(); + assert data != null; + binding.newFileContent.setText(data.getStringExtra("fileContentFromActivity")); + } + }); + private void processNewFile() { String newFileName = binding.newFileName.getText() != null ? binding.newFileName.getText().toString() : ""; @@ -170,7 +192,6 @@ public class CreateFileActivity extends BaseActivity { case FILE_ACTION_EDIT: editFile(repository.getOwner(), repository.getName(), filePath, AppUtil.encodeBase64(newFileContent), newFileCommitMessage, newFileBranchName, fileSha); break; - } } @@ -179,9 +200,11 @@ public class CreateFileActivity extends BaseActivity { CreateFileOptions createNewFileJsonStr = new CreateFileOptions(); createNewFileJsonStr.setContent(fileContent); createNewFileJsonStr.setMessage(fileCommitMessage); + if(branches.contains(branchName)) { createNewFileJsonStr.setBranch(branchName); - } else { + } + else { createNewFileJsonStr.setNewBranch(branchName); } @@ -189,50 +212,47 @@ public class CreateFileActivity extends BaseActivity { .getApiInterface(ctx) .repoCreateFile(createNewFileJsonStr, repoOwner, repoName, fileName); - call.enqueue(new Callback() { + call.enqueue(new Callback<>() { - @Override - public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { - switch(response.code()) { + switch(response.code()) { - case 201: - enableProcessButton(); - Toasty.success(ctx, getString(R.string.newFileSuccessMessage)); - Intent result = new Intent(); - result.putExtra("fileModified", true); - result.putExtra("fileAction", fileAction); - setResult(200, result); - finish(); - break; + case 201: + enableProcessButton(); + Toasty.success(ctx, getString(R.string.newFileSuccessMessage)); + Intent result = new Intent(); + result.putExtra("fileModified", true); + result.putExtra("fileAction", fileAction); + setResult(200, result); + finish(); + break; - case 401: - enableProcessButton(); - AlertDialogs.authorizationTokenRevokedDialog(ctx); - break; + case 401: + enableProcessButton(); + AlertDialogs.authorizationTokenRevokedDialog(ctx); + break; - case 404: - enableProcessButton(); - Toasty.warning(ctx, getString(R.string.apiNotFound)); - break; + case 404: + enableProcessButton(); + Toasty.warning(ctx, getString(R.string.apiNotFound)); + break; - default: - enableProcessButton(); - Toasty.error(ctx, getString(R.string.genericError)); - break; + default: + enableProcessButton(); + Toasty.error(ctx, getString(R.string.genericError)); + break; + } + } - } - } + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - enableProcessButton(); - - } + Log.e("onFailure", t.toString()); + enableProcessButton(); + } }); - } private void deleteFile(String repoOwner, String repoName, String fileName, String fileCommitMessage, String branchName, String fileSha) { @@ -240,9 +260,11 @@ public class CreateFileActivity extends BaseActivity { DeleteFileOptions deleteFileJsonStr = new DeleteFileOptions(); deleteFileJsonStr.setMessage(fileCommitMessage); deleteFileJsonStr.setSha(fileSha); + if(branches.contains(branchName)) { deleteFileJsonStr.setBranch(branchName); - } else { + } + else { deleteFileJsonStr.setNewBranch(branchName); } @@ -250,7 +272,7 @@ public class CreateFileActivity extends BaseActivity { .getApiInterface(ctx) .repoDeleteFileWithBody(repoOwner, repoName, fileName, deleteFileJsonStr); - call.enqueue(new Callback() { + call.enqueue(new Callback<>() { @Override public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { @@ -281,7 +303,6 @@ public class CreateFileActivity extends BaseActivity { enableProcessButton(); Toasty.info(ctx, getString(R.string.genericError)); break; - } } @@ -292,7 +313,6 @@ public class CreateFileActivity extends BaseActivity { enableProcessButton(); } }); - } private void editFile(String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName, String fileSha) { @@ -301,9 +321,11 @@ public class CreateFileActivity extends BaseActivity { editFileJsonStr.setContent(fileContent); editFileJsonStr.setMessage(fileCommitMessage); editFileJsonStr.setSha(fileSha); + if(branches.contains(branchName)) { editFileJsonStr.setBranch(branchName); - } else { + } + else { editFileJsonStr.setNewBranch(branchName); } @@ -311,7 +333,7 @@ public class CreateFileActivity extends BaseActivity { .getApiInterface(ctx) .repoUpdateFile(editFileJsonStr, repoOwner, repoName, fileName); - call.enqueue(new Callback() { + call.enqueue(new Callback<>() { @Override public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { @@ -342,7 +364,6 @@ public class CreateFileActivity extends BaseActivity { enableProcessButton(); Toasty.info(ctx, getString(R.string.genericError)); break; - } } @@ -351,10 +372,8 @@ public class CreateFileActivity extends BaseActivity { Log.e("onFailure", t.toString()); enableProcessButton(); - } }); - } private void getBranches(String repoOwner, String repoName) { @@ -363,33 +382,32 @@ public class CreateFileActivity extends BaseActivity { .getApiInterface(ctx) .repoListBranches(repoOwner, repoName, null, null); - call.enqueue(new Callback>() { + call.enqueue(new Callback<>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull retrofit2.Response> response) { + @Override + public void onResponse(@NonNull Call> call, @NonNull retrofit2.Response> response) { - if(response.code() == 200) { + if(response.code() == 200) { - assert response.body() != null; - for(Branch branch : response.body()) branches.add(branch.getName()); + assert response.body() != null; + for(Branch branch : response.body()) + branches.add(branch.getName()); - ArrayAdapter adapter = new ArrayAdapter<>(CreateFileActivity.this, R.layout.list_spinner_items, branches); + ArrayAdapter adapter = new ArrayAdapter<>(CreateFileActivity.this, R.layout.list_spinner_items, branches); - binding.newFileBranches.setAdapter(adapter); - binding.newFileBranches.setText(repository.getBranchRef(), false); + binding.newFileBranches.setAdapter(adapter); + binding.newFileBranches.setText(repository.getBranchRef(), false); - enableProcessButton(); + enableProcessButton(); + } + } - } - } + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - } + Log.e("onFailure", t.toString()); + } }); - } private void disableProcessButton() { binding.newFileCreate.setEnabled(false); } @@ -400,5 +418,4 @@ public class CreateFileActivity extends BaseActivity { super.onResume(); repository.checkAccountSwitch(this); } - } diff --git a/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageManager.java b/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageManager.java index 6c5816a2..52e6656f 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageManager.java +++ b/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageManager.java @@ -5,6 +5,7 @@ import com.amrdeveloper.codeview.Code; import com.amrdeveloper.codeview.CodeView; import org.mian.gitnex.helpers.codeeditor.languages.GoLanguage; import org.mian.gitnex.helpers.codeeditor.languages.JavaLanguage; +import org.mian.gitnex.helpers.codeeditor.languages.PhpLanguage; import org.mian.gitnex.helpers.codeeditor.languages.PythonLanguage; import java.util.ArrayList; import java.util.HashSet; @@ -36,8 +37,9 @@ public class LanguageManager { public String[] getLanguageKeywords(LanguageName language) { switch (language) { case JAVA: return JavaLanguage.getKeywords(context); - case PYTHON: return PythonLanguage.getKeywords(context); - case GO_LANG: return GoLanguage.getKeywords(context); + case PY: return PythonLanguage.getKeywords(context); + case GO: return GoLanguage.getKeywords(context); + case PHP: return PhpLanguage.getKeywords(context); default: return new String[]{}; } } @@ -45,8 +47,9 @@ public class LanguageManager { public List getLanguageCodeList(LanguageName language) { switch (language) { case JAVA: return JavaLanguage.getCodeList(context); - case PYTHON: return PythonLanguage.getCodeList(context); - case GO_LANG: return GoLanguage.getCodeList(context); + case PY: return PythonLanguage.getCodeList(context); + case GO: return GoLanguage.getCodeList(context); + case PHP: return PhpLanguage.getCodeList(context); default: return new ArrayList<>(); } } @@ -54,8 +57,9 @@ public class LanguageManager { public Set getLanguageIndentationStarts(LanguageName language) { switch (language) { case JAVA: return JavaLanguage.getIndentationStarts(); - case PYTHON: return PythonLanguage.getIndentationStarts(); - case GO_LANG: return GoLanguage.getIndentationStarts(); + case PY: return PythonLanguage.getIndentationStarts(); + case GO: return GoLanguage.getIndentationStarts(); + case PHP: return PhpLanguage.getIndentationStarts(); default: return new HashSet<>(); } } @@ -63,8 +67,9 @@ public class LanguageManager { public Set getLanguageIndentationEnds(LanguageName language) { switch (language) { case JAVA: return JavaLanguage.getIndentationEnds(); - case PYTHON: return PythonLanguage.getIndentationEnds(); - case GO_LANG: return GoLanguage.getIndentationEnds(); + case PY: return PythonLanguage.getIndentationEnds(); + case GO: return GoLanguage.getIndentationEnds(); + case PHP: return PhpLanguage.getIndentationEnds(); default: return new HashSet<>(); } } @@ -74,12 +79,15 @@ public class LanguageManager { case JAVA: JavaLanguage.applyFiveColorsDarkTheme(context, codeView); break; - case PYTHON: + case PY: PythonLanguage.applyFiveColorsDarkTheme(context, codeView); break; - case GO_LANG: + case GO: GoLanguage.applyFiveColorsDarkTheme(context, codeView); break; + case PHP: + PhpLanguage.applyFiveColorsDarkTheme(context, codeView); + break; } } } diff --git a/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageName.java b/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageName.java index fcbea752..ac7ba22b 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageName.java +++ b/app/src/main/java/org/mian/gitnex/helpers/codeeditor/LanguageName.java @@ -6,7 +6,9 @@ package org.mian.gitnex.helpers.codeeditor; */ public enum LanguageName { - JAVA, - PYTHON, - GO_LANG + UNKNOWN, // no language is specified or app currently does not support the mentioned language + JAVA, // java + PY, // python with py extension + GO, // go lang + PHP // php } diff --git a/app/src/main/java/org/mian/gitnex/helpers/codeeditor/languages/PhpLanguage.java b/app/src/main/java/org/mian/gitnex/helpers/codeeditor/languages/PhpLanguage.java new file mode 100644 index 00000000..4548f483 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/helpers/codeeditor/languages/PhpLanguage.java @@ -0,0 +1,101 @@ +package org.mian.gitnex.helpers.codeeditor.languages; + +import android.content.Context; +import android.content.res.Resources; +import com.amrdeveloper.codeview.Code; +import com.amrdeveloper.codeview.CodeView; +import com.amrdeveloper.codeview.Keyword; +import org.mian.gitnex.R; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * @author M M Arif + */ + +public class PhpLanguage { + + //Language Keywords + private static final Pattern PATTERN_KEYWORDS = Pattern.compile("\\b(php|__construct|var_dump|define|echo|var|float|" + + "int|bool|false|true|function|private|public|protected|interface|return|copy|struct|abstract|extends|" + + "trait|static|namespace|implements|__set|__get|unlink|this|try|catch|Throwable|Exception|pdo|" + + "str_replace|form|date|abs|min|max|strtotime|mktime|" + + "foreach|require_once|include_once|hash|array|range|break|continue|preg_match|preg_match_all|preg_replace|" + + "throw|new|and|or|if|else|elseif|switch|case|default|match|require|include|goto|do|while|for|map|)\\b"); + + //Brackets and Colons + private static final Pattern PATTERN_BUILTINS = Pattern.compile("[,:;[->]{}()]"); + + //Data + private static final Pattern PATTERN_NUMBERS = Pattern.compile("\\b(\\d*[.]?\\d+)\\b"); + private static final Pattern PATTERN_CHAR = Pattern.compile("['](.*?)[']"); + private static final Pattern PATTERN_STRING = Pattern.compile("[\"](.*?)[\"]"); + private static final Pattern PATTERN_HEX = Pattern.compile("0x[0-9a-fA-F]+"); + private static final Pattern PATTERN_SINGLE_LINE_COMMENT = Pattern.compile("//[^\\n]*"); + private static final Pattern PATTERN_MULTI_LINE_COMMENT = Pattern.compile("/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*/"); + private static final Pattern PATTERN_ATTRIBUTE = Pattern.compile("\\.[a-zA-Z0-9_]+"); + private static final Pattern PATTERN_OPERATION =Pattern.compile( ":|==|>|<|!=|>=|<=|->|=|>|<|%|-|-=|%=|\\+|\\-|\\-=|\\+=|\\^|\\&|\\|::|\\?|\\*"); + + public static void applyFiveColorsDarkTheme(Context context, CodeView codeView) { + codeView.resetSyntaxPatternList(); + codeView.resetHighlighter(); + + Resources resources = context.getResources(); + + //View Background + codeView.setBackgroundColor(resources.getColor(R.color.five_dark_black, null)); + + //Syntax Colors + codeView.addSyntaxPattern(PATTERN_HEX, resources.getColor(R.color.five_dark_purple, null)); + codeView.addSyntaxPattern(PATTERN_CHAR, resources.getColor(R.color.five_dark_yellow, null)); + codeView.addSyntaxPattern(PATTERN_STRING, resources.getColor(R.color.five_dark_yellow, null)); + codeView.addSyntaxPattern(PATTERN_NUMBERS, resources.getColor(R.color.five_dark_purple, null)); + codeView.addSyntaxPattern(PATTERN_KEYWORDS, resources.getColor(R.color.five_dark_purple, null)); + codeView.addSyntaxPattern(PATTERN_BUILTINS, resources.getColor(R.color.five_dark_white, null)); + codeView.addSyntaxPattern(PATTERN_SINGLE_LINE_COMMENT, resources.getColor(R.color.five_dark_grey, null)); + codeView.addSyntaxPattern(PATTERN_MULTI_LINE_COMMENT, resources.getColor(R.color.five_dark_grey, null)); + codeView.addSyntaxPattern(PATTERN_ATTRIBUTE, resources.getColor(R.color.five_dark_blue, null)); + codeView.addSyntaxPattern(PATTERN_OPERATION, resources.getColor(R.color.five_dark_purple, null)); + + //Default Color + codeView.setTextColor(resources.getColor(R.color.five_dark_white, null)); + + codeView.reHighlightSyntax(); + } + + public static String[] getKeywords(Context context) { + return context.getResources().getStringArray(R.array.php_keywords); + } + + public static List getCodeList(Context context) { + List codeList = new ArrayList<>(); + String[] keywords = getKeywords(context); + for (String keyword : keywords) { + codeList.add(new Keyword(keyword)); + } + return codeList; + } + + public static Set getIndentationStarts() { + Set characterSet = new HashSet<>(); + characterSet.add('{'); + return characterSet; + } + + public static Set getIndentationEnds() { + Set characterSet = new HashSet<>(); + characterSet.add('}'); + return characterSet; + } + + public static String getCommentStart() { + return "//"; + } + + public static String getCommentEnd() { + return ""; + } +} diff --git a/app/src/main/res/layout/activity_create_file.xml b/app/src/main/res/layout/activity_create_file.xml index dc05c3d4..f0399de9 100644 --- a/app/src/main/res/layout/activity_create_file.xml +++ b/app/src/main/res/layout/activity_create_file.xml @@ -81,7 +81,6 @@ android:textColor="?attr/inputTextColor" android:textColorHighlight="?attr/hintColor" android:textColorHint="?attr/hintColor" - android:inputType="textCapSentences" android:singleLine="true" android:imeOptions="actionNext" android:textSize="@dimen/dimen16sp" /> @@ -105,17 +104,28 @@ + android:textSize="@dimen/dimen14sp" /> + + + app:menu="@menu/drawer_menu" /> diff --git a/app/src/main/res/values/languages.xml b/app/src/main/res/values/languages.xml index cc8ca780..e0629fda 100644 --- a/app/src/main/res/values/languages.xml +++ b/app/src/main/res/values/languages.xml @@ -1,6 +1,81 @@ + + + php + __construct + var_dump + define + echo + var + float + int + bool + false + true + function + private + public + protected + interface + return + copy + struct + abstract + extends + trait + static + namespace + implements + __set + __get + unlink + this + try + catch + Throwable + Exception + pdo + throw + new + and + or + if + else + elseif + switch + case + default + match + require + include + require_once + include_once + goto + do + while + for + foreach + map + hash + array + range + break + continue + preg_match + preg_match_all + preg_replace + str_replace + form + date + abs + min + max + strtotime + mktime + + public diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2e226f5c..e58a8bab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -784,4 +784,5 @@ %1$d:%2$d Code Editor + Open in Code Editor