- Removed unused libraries

- Added about page with licenses to open source libraries
This commit is contained in:
itsaky
2021-08-07 11:43:15 +05:30
parent f99d51ca42
commit feffb8a3c7
126 changed files with 895 additions and 7049 deletions
+6 -9
View File
@@ -29,7 +29,8 @@ android {
disable "VectorPath",
"NestedWeights",
"UnusedResources",
"ContentDescription"
"ContentDescription",
"SmallSp"
}
buildFeatures.viewBinding true
@@ -59,7 +60,7 @@ android {
stringfog.enable false
}
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
stringfog.enable true
@@ -75,9 +76,8 @@ android {
}
stringfog {
def isRelease = getGradle().getStartParameter().getTaskRequests().toString().contains("release")
key 'WVV0aGMwaEFZVzVFVW05SlJFbGtaUT09'
enable false
enable true
implementation 'com.github.megatronking.stringfog.xor.StringFogImpl'
}
@@ -101,9 +101,9 @@ dependencies {
// AndroidX
implementation 'androidx.annotation:annotation:1.2.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
implementation 'androidx.multidex:multidex:2.0.1'
@@ -121,9 +121,6 @@ dependencies {
// Local projects
implementation project(':treeview')
implementation project(':spinkit')
implementation project(':slidr')
implementation project(':javadocparser')
implementation project(':lsp')
implementation fileTree(dir: 'libs', include: ['*.jar'])
+16 -2
View File
@@ -1,4 +1,5 @@
-keepattributes SourceFile, LineNumberTable
-keepattributes Signature
-keepattributes *Annotation*
-renamesourcefileattribute FuckYou
-obfuscationdictionary dictionary.txt
-packageobfuscationdictionary dictionary.txt
@@ -8,10 +9,16 @@
-dontwarn
-dontnote
-dontwarn sun.misc.**
-dontwarn android.arch.**
-dontwarn android.lifecycle.**
-keep class android.arch.** { *; }
-keep class android.lifecycle.** { *; }
-keep class com.google.gson.examples.android.model.** { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
-dontwarn androidx.arch.**
-dontwarn androidx.lifecycle.**
@@ -19,10 +26,17 @@
-keep class androidx.lifecycle.** { *; }
-keepclasseswithmembernames,includedescriptorclasses class * { native <methods>; }
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule { <init>(...); }
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { *** rewind(); }
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { *** rewind(); }
+5
View File
@@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application
tools:ignore="UnusedAttribute"
android:name=".app.StudioApp"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -44,6 +45,10 @@
android:name=".PreferencesActivity"
android:configChanges="orientation|screenSize">
</activity>
<activity
android:name=".AboutActivity"
android:configChanges="orientation|screenSize|uiMode">
</activity>
<service
android:name="com.itsaky.androidide.services.IDEService"
android:exported="false">
+62
View File
@@ -0,0 +1,62 @@
[
{
"name": "AndroidX Libraries",
"license": "Apache License 2.0",
"url": "https://github.com/androidx/androidx"
},
{
"name": "Material Components for Android",
"license": "Apache License 2.0",
"url": "https://github.com/material-components/material-components-android"
},
{
"name": "Gson",
"license": "Apache License 2.0",
"url": "https://github.com/google/gson"
},
{
"name": "Guava",
"license": "Apache License 2.0",
"url": "https://github.com/google/guava"
},
{
"name": "ANTLR4",
"license": "The 3-Clause BSD License",
"url": "https://github.com/antlr/antlr4"
},
{
"name": "Glide",
"license": "BSD, part MIT and Apache 2.0",
"url": "https://github.com/bumptech/glide"
},
{
"name": "Android UtilCode",
"license": "Apache License 2.0",
"url": "https://github.com/Blankj/AndroidUtilCode"
},
{
"name": "UnicornFilePicker",
"license": "Apache License 2.0",
"url": "https://github.com/abhishekti7/UnicornFilePicker"
},
{
"name": "QuickAction",
"license": "Apache License 2.0",
"url": "https://github.com/piruin/quickaction"
},
{
"name": "XmlToJson",
"license": "Apache License 2.0",
"url": "https://github.com/smart-fun/XmlToJson"
},
{
"name": "AndroidTreeView",
"license": "Apache License 2.0",
"url": "https://github.com/bmelnychuk/AndroidTreeView"
},
{
"name": "CodeEditor",
"license": "GPL-3.0 License",
"url": "https://github.com/Rosemoe/CodeEditor"
}
]
@@ -0,0 +1,61 @@
package com.itsaky.androidide;
import android.os.Bundle;
import android.view.View;
import com.itsaky.androidide.app.StudioActivity;
import com.itsaky.androidide.databinding.ActivityAboutBinding;
import com.itsaky.androidide.fragments.sheets.OptionsListFragment;
import com.itsaky.androidide.models.License;
import com.itsaky.androidide.tasks.TaskExecutor;
import com.itsaky.androidide.tasks.callables.LicenseReader;
import java.util.List;
public class AboutActivity extends StudioActivity {
private ActivityAboutBinding binding;
@Override
protected View bindLayout() {
binding = ActivityAboutBinding.inflate(getLayoutInflater());
return binding.getRoot();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding.items.footerText.setText(getFooter());
new TaskExecutor().executeAsync(new LicenseReader(this), __ -> {
setupLicenses(__);
});
}
private void setupLicenses(List<License> licenses) {
if(licenses == null || licenses.size() <= 0) {
binding.items.licenses.setText(getString(R.string.msg_about_no_licenses));
} else {
StringBuilder sb = new StringBuilder();
for(License license : licenses) {
sb.append("\u2022 ");
sb.append(license.name);
sb.append("\n");
sb.append(getString(R.string.msg_about_licensed_under, license.license));
sb.append("\n");
sb.append(getString(R.string.msg_about_license_source, license.url));
sb.append("\n\n");
}
binding.items.licenses.setText(sb);
}
}
private String getFooter() {
final String arch = android.os.Build.SUPPORTED_ABIS[0];
try {
final String version = getPackageManager().getPackageInfo("com.itsaky.androidide", 0).versionName;
return getString(R.string.about_footer, version, arch);
} catch (Throwable th) {
return getString(R.string.about_footer_alternate, arch);
}
}
}
@@ -1121,6 +1121,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
if(i >= 0 && !mBinding.tabs.getTabAt(i).isSelected())
mBinding.tabs.getTabAt(i).select();
mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END);
invalidateOptionsMenu();
}
@Override
@@ -1521,5 +1522,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
DidCloseTextDocumentParams p = new DidCloseTextDocumentParams();
p.textDocument = id;
didClose(p);
invalidateOptionsMenu();
}
}
@@ -28,7 +28,6 @@ public class PreferencesActivity extends StudioActivity {
setSupportActionBar(binding.toolbar);
getSupportActionBar().setTitle(R.string.ide_preferences);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
loadFragment(getPrefsFragment());
}
@@ -47,7 +47,7 @@ public class SymbolInputAdapter extends RecyclerView.Adapter<SymbolInputAdapter.
if(symbols == null || symbols[position] == null) return;
final Symbol symbol = symbols[position];
holder.binding.symbol.setText(symbol.label);
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(holder.binding.symbol, 16, 27, 1, TypedValue.COMPLEX_UNIT_SP);
// TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(holder.binding.symbol, 16, 27, 1, TypedValue.COMPLEX_UNIT_SP);
holder.binding.symbol.setOnClickListener(__ -> channel.insertSymbol(symbol.commit, symbol.offset));
}
@@ -7,7 +7,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import androidx.core.content.ContextCompat;
import com.github.ybq.android.spinkit.style.Circle;
import com.itsaky.androidide.R;
import com.itsaky.androidide.app.StudioActivity;
import com.itsaky.androidide.databinding.LayoutFiletreeItemBinding;
@@ -60,7 +59,6 @@ public class FileTreeViewHolder extends TreeNode.BaseNodeViewHolder<File> {
}
public void setLoading() {
chevron.setImageDrawable(new Circle());
chevron.getDrawable().setColorFilter(ContextCompat.getColor(context, R.color.secondaryLightColor), PorterDuff.Mode.SRC_ATOP);
}
@@ -75,7 +75,8 @@ public class StudioApp extends MultiDexApplication
public static final String TELEGRAM_GROUP_URL = "https://t.me/androidide_discussions";
public static final String SUGGESTIONS_URL = "https://github.com/itsaky/AndroidIDE";
public static final String WEBSITE = "https://androidide.com";
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
@Override
@@ -338,6 +339,7 @@ public class StudioApp extends MultiDexApplication
return new File(getFilesDir(), "framework");
}
@SuppressLint("SdCardPath")
public File getIDEDataDir() {
return Environment.mkdirIfNotExits(new File("/data/data/com.itsaky.androidide/files"));
}
@@ -489,4 +491,12 @@ public class StudioApp extends MultiDexApplication
open.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(open);
}
public void openWebsite() {
Intent open = new Intent();
open.setAction(Intent.ACTION_VIEW);
open.setData(Uri.parse(StudioApp.WEBSITE));
open.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(open);
}
}
@@ -310,13 +310,14 @@ public class EditorFragment extends BaseFragment implements EditorEventListener
@Override
public void afterDelete(CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence deletedContent) {
isModified = true;
requestSignature();
}
@Override
public void afterInsert(CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence insertedContent) {
isModified = true;
if(getFile() != null && getFile().getName().endsWith(".java")) {
if(getFile() != null && getFile().getName().endsWith(EXT_XML)) {
boolean isOpen = false;
try {
isOpen = editor.getText().charAt(editor.getCursor().getLeft() - 2) == '<';
@@ -326,10 +327,7 @@ public class EditorFragment extends BaseFragment implements EditorEventListener
}
}
char c = insertedContent.charAt(0);
if(c == '(' || c == ',') {
requestSignature();
}
requestSignature();
}
private void requestSignature() {
@@ -1,5 +1,6 @@
package com.itsaky.androidide.fragments.preferences;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.Spannable;
@@ -13,13 +14,13 @@ import androidx.core.content.ContextCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.blankj.utilcode.util.ResourceUtils;
import com.blankj.utilcode.util.ThrowableUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.itsaky.androidide.R;
import com.itsaky.androidide.AboutActivity;
import com.itsaky.androidide.app.StudioApp;
import org.json.JSONArray;
import org.json.JSONObject;
import com.blankj.utilcode.util.SizeUtils;
public class IDEPreferences extends BasePreferenceFragment {
@@ -35,6 +36,7 @@ public class IDEPreferences extends BasePreferenceFragment {
public static final String KEY_TELEGRAM = "idepref_telegram";
public static final String KEY_ISSUES = "idepref_issues";
public static final String KEY_CHANGELOG = "idepref_changelog";
public static final String KEY_ABOUT = "idepref_about";
@Override
public void onCreatePreferences(Bundle savedState, String rootKey) {
@@ -48,7 +50,8 @@ public class IDEPreferences extends BasePreferenceFragment {
final Preference telegram = new Preference(getContext());
final Preference issueTracker = new Preference(getContext());
final Preference changelog = new Preference(getContext());
final Preference about = new Preference(getContext());
appearance.setKey(KEY_APPEARANCE);
appearance.setIconSpaceReserved(false);
appearance.setFragment(getAppearanceFrag().getClass().getName());
@@ -81,17 +84,24 @@ public class IDEPreferences extends BasePreferenceFragment {
changelog.setIconSpaceReserved(false);
changelog.setTitle(R.string.pref_changelog);
changelog.setSummary(R.string.pref_changelog_summary);
about.setKey(KEY_ABOUT);
about.setIconSpaceReserved(false);
about.setTitle(R.string.idepref_about_title);
// about.setSummary(R.string.pref_changelog_summary);
screen.addPreference(editor);
screen.addPreference(build);
screen.addPreference(issueTracker);
screen.addPreference(telegram);
screen.addPreference(changelog);
screen.addPreference(about);
final Preference.OnPreferenceClickListener listener = getListener();
issueTracker.setOnPreferenceClickListener(listener);
telegram.setOnPreferenceClickListener(listener);
changelog.setOnPreferenceClickListener(listener);
about.setOnPreferenceClickListener(listener);
}
private AppearancePreferences getAppearanceFrag() {
@@ -161,7 +171,9 @@ public class IDEPreferences extends BasePreferenceFragment {
StudioApp.getInstance().openTelegramGroup();
} else if(key.equals(KEY_ISSUES)) {
StudioApp.getInstance().openIssueTracker();
}
} else if(key.equals(KEY_ABOUT)) {
startActivity(new Intent(getContext(), AboutActivity.class));
}
return true;
}
};
@@ -13,16 +13,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.view.MotionEvent;
import android.graphics.Rect;
import com.r0adkll.slidr.model.SlidrInterface;
import com.r0adkll.slidr.Slidr;
import com.r0adkll.slidr.model.SlidrConfig;
import com.r0adkll.slidr.model.SlidrPosition;
public abstract class BaseBottomSheetFragment extends BottomSheetDialogFragment {
protected Dialog mDialog;
private LayoutSheetBinding binding;
protected boolean shadowEnabled = true;
protected boolean titleEnabled = true;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -78,7 +75,7 @@ public abstract class BaseBottomSheetFragment extends BottomSheetDialogFragment
}
protected boolean shouldHideTitle() {
return false;
return !titleEnabled;
}
protected String getTitle() {
@@ -88,6 +85,10 @@ public abstract class BaseBottomSheetFragment extends BottomSheetDialogFragment
public void setShowShadow(boolean enabled) {
this.shadowEnabled = enabled;
}
public void setShowTitle(boolean enabled) {
this.titleEnabled = enabled;
}
protected void onShow() {}
protected abstract void bind(LinearLayout container);
@@ -10,6 +10,7 @@ import android.widget.TextView;
import com.blankj.utilcode.util.ThrowableUtils;
import com.itsaky.androidide.R;
import com.itsaky.androidide.models.LogLine;
import android.annotation.SuppressLint;
public class LogSheet extends BaseBottomSheetFragment {
@@ -51,6 +52,7 @@ public class LogSheet extends BaseBottomSheetFragment {
}
}
@SuppressLint("SetTextI18n")
protected TextView createLogTextView(LogLine line) {
TextView text = new TextView(getContext());
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
@@ -16,6 +16,8 @@ public class OptionsListFragment extends BaseBottomSheetFragment {
private RecyclerView mList;
private OnOptionsClickListener listener;
private final List<SheetOption> mOptions = new ArrayList<>();
protected boolean dismissOnItemClick = true;
@Override
protected void bind(LinearLayout container) {
@@ -28,7 +30,12 @@ public class OptionsListFragment extends BaseBottomSheetFragment {
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mList.setLayoutManager(new LinearLayoutManager(getContext()));
mList.setAdapter(new OptionsSheetAdapter(mOptions, __ -> { dismiss(); if(listener != null) listener.onOptionsClick(__);}));
mList.setAdapter(new OptionsSheetAdapter(mOptions, __ -> {
if(dismissOnItemClick)
dismiss();
if(listener != null)
listener.onOptionsClick(__);
}));
}
public OptionsListFragment setOnOptionsClickListener(OnOptionsClickListener listener) {
@@ -52,6 +59,11 @@ public class OptionsListFragment extends BaseBottomSheetFragment {
mOptions.remove(option);
return this;
}
public OptionsListFragment setDismissOnItemClick(boolean dissmiss) {
this.dismissOnItemClick = dissmiss;
return this;
}
@Override
protected String getTitle() {
@@ -5,7 +5,6 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import com.github.ybq.android.spinkit.style.FoldingCube;
import com.itsaky.androidide.databinding.LayoutProgressSheetBinding;
import com.blankj.utilcode.util.SizeUtils;
import android.widget.RelativeLayout;
@@ -13,7 +12,7 @@ import android.widget.RelativeLayout;
public class ProgressSheet extends BaseBottomSheetFragment {
private LayoutProgressSheetBinding binding;
private Drawable drawable = new FoldingCube();
private Drawable drawable = null;
private String message = "";
private String subMessage = "";
private boolean subMessageEnabled = false;
@@ -44,7 +44,7 @@ public class TextSheetFragment extends BaseBottomSheetFragment {
@Override
protected void onShow() {
super.onShow();
setToEditor(SpannableString.valueOf(getOutputBuilder()));
editor.setText(getOutputBuilder());
}
private Void scrollToBottom() {
@@ -48,6 +48,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import com.itsaky.lsp.DidChangeWatchedFilesParams;
import com.itsaky.lsp.SignatureHelp;
import android.annotation.SuppressLint;
public class JavaLanguageServer implements ShellServer.Callback {
@@ -136,6 +137,7 @@ public class JavaLanguageServer implements ShellServer.Callback {
return server;
}
@SuppressLint("NewApi")
protected void sendInit() {
InitializeParams p = new InitializeParams();
p.rootUri = new File(project.getProjectPath()).toURI();
@@ -267,41 +269,12 @@ public class JavaLanguageServer implements ShellServer.Callback {
@Override
public void output(CharSequence charSequence) {
writeOut(charSequence.toString());
}
private BufferedOutputStream os;
private BufferedOutputStream os1;
private void writeOut(String data) {
try {
if(os == null) {
os = new BufferedOutputStream(new FileOutputStream(new File(FileUtil.getExternalStorageDir(), "ide_xlog/out.txt"), true));
}
os.write(data.getBytes());
os.flush();
} catch (Throwable th) {
logger.e(ThrowableUtils.getFullStackTrace(th));
}
}
private void writeOut2(String data) {
try {
if(os1 == null) {
os1 = new BufferedOutputStream(new FileOutputStream(new File(FileUtil.getExternalStorageDir(), "ide_xlog/verbose.txt"), true));
}
os1.write(data.getBytes());
os1.flush();
} catch (Throwable th) {
logger.e(ThrowableUtils.getFullStackTrace(th));
}
}
/**
* This method is called on UI Thread, do not perform time consuming or networking tasks
*/
private void onServerOut(String line) {
writeOut2(line + "\n");
if(line.contains(CONTENT_LENGTH)) line = line.substring(0, line.lastIndexOf(CONTENT_LENGTH));
if(this.client == null) return;
try {
@@ -13,6 +13,7 @@ import com.itsaky.lsp.TextEdit;
import io.github.rosemoe.editor.text.Cursor;
import io.github.rosemoe.editor.widget.CodeEditor;
import java.util.List;
import com.itsaky.androidide.language.java.manager.JavaCharacter;
public class CompletionItemWrapper implements SuggestItem, Comparable {
@@ -58,12 +59,21 @@ public class CompletionItemWrapper implements SuggestItem, Comparable {
try {
final Cursor cursor = editor.getCursor();
if(cursor.isSelected()) return;
final int length = getInsertLength();
final int line = cursor.getLeftLine();
int col = cursor.getLeftColumn();
while(true) {
col--;
if(col == 0)
break;
if(!JavaCharacter.isJavaIdentifierPart(editor.getText().charAt(line, col)))
break;
}
col++;
String text = getInsertText();
final boolean shiftLeft = text.contains("$0");
final boolean atEnd = text.endsWith("$0");
text = text.replace("$0", "");
editor.getText().delete(cursor.getLeftLine(), cursor.getLeftColumn() - length, cursor.getLeftLine(), cursor.getLeftColumn());
editor.getText().delete(line, col, line, cursor.getLeftColumn());
cursor.onCommitText(text);
if(shiftLeft && !atEnd) {
@@ -0,0 +1,14 @@
package com.itsaky.androidide.models;
import com.google.gson.annotations.SerializedName;
public class License {
@SerializedName("name")
public String name;
@SerializedName("license")
public String license;
@SerializedName("url")
public String url;
}
@@ -47,7 +47,7 @@ public class LogLine {
if(s == null || s.trim().length() > 1) {
return DEBUG;
}
char c = s.toLowerCase().charAt(0);
char c = s.toLowerCase(Locale.US).charAt(0);
if(c == 'w') {
return WARNING;
} else if(c == 'e') {
@@ -15,6 +15,9 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.CharStreams;
import java.util.Map;
import java.util.HashMap;
import com.itsaky.lsp.Position;
public class JavaLexerImpl extends BaseJavaLexer implements Lexer {
@@ -30,7 +33,7 @@ public class JavaLexerImpl extends BaseJavaLexer implements Lexer {
this.isFirst = true;
builtinTypes = new ArrayList<>();
builtinTypes.add(JavaLexer.BOOLEAN);
builtinTypes.add(JavaLexer.BYTE);
builtinTypes.add(JavaLexer.CHAR);
@@ -154,6 +157,11 @@ public class JavaLexerImpl extends BaseJavaLexer implements Lexer {
type = TokenType.STRING_LITERAL;
colors.addIfNeeded(line, column, EditorColorScheme.LITERAL);
wasClassName = false;
Position start = new Position(line, column);
Position end = new Position(line, column + currentToken.getText().length());
colors.addStringRange(line, new Range(start, end));
addHexColorIfPresent();
break;
case JavaLexer.LPAREN :
@@ -5,6 +5,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
public class Token implements Serializable {
@@ -76,9 +77,9 @@ public class Token implements Serializable {
@Override
public String toString() {
if (pairValue == 0) {
return String.format("%s (%d, %d) %d", type, line, column, length);
return String.format(Locale.US, "%s (%d, %d) %d", type, line, column, length);
} else {
return String.format("%s (%d, %d) (%d) %d", type, line, column, length, pairValue);
return String.format(Locale.US, "%s (%d, %d) (%d) %d", type, line, column, length, pairValue);
}
}
@@ -0,0 +1,31 @@
package com.itsaky.androidide.tasks.callables;
import android.content.Context;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.itsaky.androidide.models.License;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;
import java.util.concurrent.Callable;
public class LicenseReader implements Callable<List<License>> {
private final Context ctx;
public LicenseReader(Context ctx) {
this.ctx = ctx;
}
@Override
public List<License> call() throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(ctx.getAssets().open("licenses.json")));
String line;
StringBuilder sb = new StringBuilder();
while((line = reader.readLine()) != null) {
sb.append(line);
}
TypeToken<List<License>> token = new TypeToken<List<License>>(){};
return new Gson().fromJson(sb.toString(), token.getType());
}
}
@@ -12,6 +12,8 @@ import android.graphics.Color;
public class TooltipLayout extends LinearLayout {
private final float dp8;
private final Path path;
private final Paint paint;
public TooltipLayout (Context ctx) {
this(ctx, null);
@@ -25,14 +27,20 @@ public class TooltipLayout extends LinearLayout {
super(ctx, attrs, style);
dp8 = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
path = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#424242"));
}
@Override
protected void onDraw(Canvas canvas) {
final int width = getWidth();
final int height = getHeight();
final float midX = width / 2;
Path path = new Path();
path.moveTo(0, 0);
path.lineTo(width, 0);
path.lineTo(width, height - dp8);
@@ -42,10 +50,6 @@ public class TooltipLayout extends LinearLayout {
path.lineTo(0, height - dp8);
path.close();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#424242"));
canvas.drawPath(path, paint);
super.onDraw(canvas);
}
@@ -20,6 +20,7 @@ import java.util.List;
import io.github.rosemoe.editor.annotations.Experimental;
import io.github.rosemoe.struct.BlockLinkedList;
import io.github.rosemoe.editor.widget.CodeEditor;
/**
* This class saves the text content for editor and maintains line widths
@@ -45,6 +46,8 @@ public class Content implements CharSequence {
private UndoManager mUndoManager;
private Cursor mCursor;
private LineRemoveListener mLineListener;
private final CodeEditor editor;
/**
* Use a BlockLinkedList instead of ArrayList.
@@ -60,8 +63,8 @@ public class Content implements CharSequence {
/**
* This constructor will create a Content object with no text
*/
public Content() {
this(null);
public Content(CodeEditor editor) {
this(editor, null);
}
/**
@@ -70,10 +73,11 @@ public class Content implements CharSequence {
*
* @param src The source of Content
*/
public Content(CharSequence src) {
public Content(CodeEditor editor, CharSequence src) {
if (src == null) {
src = "";
}
this.editor = editor;
mTextLength = 0;
mNestedBatchEdit = 0;
if (!useBlock)
@@ -607,7 +611,7 @@ public class Content implements CharSequence {
* @return sub sequence of this Content
*/
public Content subContent(int startLine, int startColumn, int endLine, int endColumn) {
Content c = new Content();
Content c = new Content(this.editor);
c.setUndoEnabled(false);
if (startLine == endLine) {
c.insert(0, 0, mLines.get(startLine).subSequence(startColumn, endColumn));
@@ -691,7 +695,7 @@ public class Content implements CharSequence {
*/
public Cursor getCursor() {
if (mCursor == null) {
mCursor = new Cursor(this);
mCursor = new Cursor(this.editor, this);
}
return mCursor;
}
@@ -20,6 +20,7 @@ import io.github.rosemoe.editor.interfaces.EditorLanguage;
import io.github.rosemoe.editor.util.IntPair;
import java.util.List;
import java.util.ArrayList;
import io.github.rosemoe.editor.widget.CodeEditor;
/**
* @author Rose
@@ -35,6 +36,8 @@ public final class Cursor {
private EditorLanguage mLanguage;
private int mTabWidth;
private final CodeEditor editor;
private final List<Character> pairs;
/**
@@ -42,7 +45,8 @@ public final class Cursor {
*
* @param content Target content
*/
public Cursor(Content content) {
public Cursor(CodeEditor editor, Content content) {
this.editor = editor;
mContent = content;
mIndexer = new CachedIndexer(content);
mLeft = new CharPosition().zero();
@@ -269,7 +273,12 @@ public final class Cursor {
&& text.charAt(0) == mContent.charAt(getLeftLine(), getLeftColumn())
&& pairs.contains(text.charAt(0))) {
set(getLeftLine(), getLeftColumn() + 1);
// Moving the cursor to right through editor is instant
// If we don't really have an instance of the editor, fall back to 'less efficient' method
if(this.editor != null)
this.editor.moveSelectionRight();
else
set(getLeftLine(), getLeftColumn() + 1);
} else {
if (mAutoIndentEnabled && text.length() != 0 && applyAutoIndent) {
char first = text.charAt(0);
@@ -311,18 +320,8 @@ public final class Cursor {
* @return Generated space string
*/
private String createIndent(int p) {
int tab = 0;
int space;
// if (mLanguage.useTab()) {
// tab = p / mTabWidth;
// space = p % mTabWidth;
// } else {
space = p;
// }
int space = p;
StringBuilder s = new StringBuilder();
for (int i = 0; i < tab; i++) {
s.append('\t');
}
for (int i = 0; i < space; i++) {
s.append(' ');
}
@@ -24,6 +24,8 @@ import io.github.rosemoe.editor.struct.Span;
import io.github.rosemoe.editor.widget.EditorColorScheme;
import java.util.HashMap;
import io.github.rosemoe.editor.struct.HexColor;
import java.util.Map;
import com.itsaky.lsp.Range;
/**
* The result of analysis
@@ -37,6 +39,8 @@ public class TextAnalyzeResult {
protected List<NavigationItem> mLabels;
protected Span mLast;
protected int mSuppressSwitch = Integer.MAX_VALUE;
private final Map<Integer, List<Range>> stringMap = new HashMap<>();
/**
* Create a new result
@@ -47,6 +51,22 @@ public class TextAnalyzeResult {
mBlocks = new ArrayList<>(1024);
mHexColor = new HashMap<>();
}
public Map<Integer, List<Range>> getStringMap() {
return stringMap;
}
public void addStringRange(int line, Range range) {
if(stringMap.containsKey(line)) {
List<Range> ranges = stringMap.get(line);
ranges.add(range);
stringMap.put(line, ranges);
} else {
List<Range> ranges = new ArrayList<>();
ranges.add(range);
stringMap.put(line, ranges);
}
}
public void addHexColor(HexColor index, int color) {
mHexColor.put(index, color);
@@ -262,6 +262,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
private Map<HexColor, Integer> mLineColors;
private Map<Range, Diagnostic> mDiagnostics;
private Map<Integer, List<Range>> stringMap;
private File currentFile;
@@ -597,6 +598,10 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
diags = new HashMap<>();
this.mDiagnostics = diags;
}
public void setStringMap(Map<Integer, List<Range>> map) {
this.stringMap = map;
}
public CodeEditor setLineColors(HashMap<HexColor, Integer> map) {
this.mLineColors = map;
@@ -3703,7 +3708,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
String t = text.toString();
t = t.replace("\t", " ");
mText = new Content(t);
mText = new Content(this, t);
mCursor = mText.getCursor();
mCursor.setAutoIndent(mAutoIndentEnabled);
mCursor.setLanguage(mLanguage);
@@ -4421,7 +4426,8 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
exitSelectModeIfNeeded();
// Auto completion
if (isAutoCompletionEnabled()) {
// Trigger only when autocompletion is enabled and cursor is not in a string token
if (isAutoCompletionEnabled() && !isInString()) {
if ((mConnection.mComposingLine == -1 || mCompletionOnComposing) && endColumn != 0 && startLine == endLine) {
int end = endColumn;
while (endColumn > 0) {
@@ -4461,6 +4467,20 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
}
}
private boolean isInString() {
final int line = getCursor().getLeftLine();
final int column = getCursor().getLeftColumn();
if(stringMap == null || stringMap.isEmpty() || !stringMap.containsKey(line)) return false;
List<Range> strings = stringMap.get(line);
if(strings == null || strings.isEmpty()) return false;
for(int i=0;i<strings.size();i++) {
Range r = strings.get(i);
if(r.start.character <= column && column <= r.end.character)
return true;
}
return false;
}
private void notifyChanged() {
if (getFile() != null && getFile().getName().endsWith(".java") && jlsRequestor != null) {
TextDocumentContentChangeEvent event = new TextDocumentContentChangeEvent();
@@ -4566,6 +4586,9 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca
if(mSpanner.getResult().getHexColors().size() > 0) {
setLineColors(mSpanner.getResult().getHexColors());
}
if(mSpanner.getResult().getStringMap().size() > 0) {
setStringMap(mSpanner.getResult().getStringMap());
}
if (mHighlightCurrentBlock) {
mCursorPosition = findCursorBlock();
}
@@ -66,13 +66,12 @@ public class SymbolChannel {
&& text.charAt(0) == mEditor.getText().charAt(cur.getLeftLine(), cur.getLeftColumn())
&& pairs.contains(text.charAt(0))) {
mEditor.moveSelectionRight();
}
mEditor.getText().insert(cur.getRightLine(), cur.getRightColumn(), text);
mEditor.notifyExternalCursorChange();
if (selectionOffset != text.length()) {
mEditor.setSelection(cur.getRightLine(), cur.getRightColumn() - (text.length() - selectionOffset));
} else {
mEditor.getText().insert(cur.getRightLine(), cur.getRightColumn(), text);
mEditor.notifyExternalCursorChange();
if (selectionOffset != text.length()) {
mEditor.setSelection(cur.getRightLine(), cur.getRightColumn() - (text.length() - selectionOffset));
}
}
}
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ffffff"
android:pathData="M22,6C22,4.9 21.1,4 20,4H4C2.9,4 2,4.9 2,6V18C2,19.1 2.9,20 4,20H20C21.1,20 22,19.1 22,18V6M20,6L12,11L4,6H20M20,18H4V8L12,13L20,8V18Z"/>
</vector>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ffffff"
android:pathData="M12,2A10,10 0,0 0,2 12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0,0 0,12 2Z"/>
</vector>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ffffff"
android:pathData="M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0,0 0,12 22A10,10 0,0 0,22 12A10,10 0,0 0,12 2Z"/>
</vector>
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/motion_about">
<View
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/icon_anchor"
android:layout_width="0dp"
android:layout_height="200dp"
android:background="@color/primaryDarkColor"/>
<com.google.android.material.card.MaterialCardView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_anchor"
android:id="@+id/icon_container"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="-28dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:cardBackgroundColor="@color/primaryLightColor"
app:cardCornerRadius="5dp"
app:cardElevation="0dp">
<ImageView
android:src="@mipmap/ic_launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/icon"/>
</com.google.android.material.card.MaterialCardView>
<TextView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_container"
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textStyle="bold"
android:textSize="30sp"
android:textColor="@color/primaryTextColor"
android:layout_marginBottom="4dp"/>
<TextView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
android:id="@+id/subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/about_subtitle"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/secondaryTextColor"
android:layout_marginBottom="24dp"/>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle"
android:id="@+id/about_scroller">
<include android:id="@+id/items" layout="@layout/layout_about_items"/>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.motion.widget.MotionLayout>
+3 -1
View File
@@ -2,6 +2,7 @@
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/editor_drawerLayout"
@@ -308,7 +309,8 @@
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"/>
android:paddingBottom="4dp"
tools:ignore="MissingConstraints"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_view"
+1 -1
View File
@@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:gravity="center"
android:id="@+id/appbar"
android:background="?attr/colorPrimary"
android:background="?attr/colorPrimaryDark"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$Behavior">
<RelativeLayout
@@ -1,20 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 2020-2021 Rosemoe
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
@@ -35,13 +19,12 @@
android:layout_width="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp">
android:paddingStart="4dp"
android:paddingEnd="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textColor="#FF000000"
android:id="@+id/result_item_label"
android:textSize="16sp"/>
@@ -49,10 +32,9 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Small Text"
android:id="@+id/result_item_desc"
android:textSize="12sp"
android:layout_marginLeft="8dp"/>
android:layout_marginStart="8dp"/>
</LinearLayout>
@@ -0,0 +1,225 @@
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:paddingTop="16dp"
android:clickable="true"
android:focusable="true"
android:background="@drawable/bg_ripple"
android:paddingStart="16dp"
android:paddingEnd="8dp">
<ImageView
android:id="@+id/icon_github"
android:layout_height="22dp"
android:layout_width="22dp"
android:scaleType="fitCenter"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_github"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="16sp"
android:textColor="@color/primaryTextColor"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/icon_github"
android:layout_centerVertical="true"
android:text="@string/user_suggestions"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:paddingTop="16dp"
android:clickable="true"
android:focusable="true"
android:background="@drawable/bg_ripple"
android:paddingStart="16dp"
android:paddingEnd="8dp">
<ImageView
android:id="@+id/icon_telegram"
android:layout_height="22dp"
android:layout_width="22dp"
android:scaleType="fitCenter"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_telegram"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="16sp"
android:textColor="@color/primaryTextColor"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/icon_telegram"
android:layout_centerVertical="true"
android:text="@string/discussions_on_telegram"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:paddingTop="16dp"
android:clickable="true"
android:focusable="true"
android:background="@drawable/bg_ripple"
android:paddingStart="16dp"
android:paddingEnd="8dp">
<ImageView
android:id="@+id/icon_email"
android:layout_height="22dp"
android:layout_width="22dp"
android:scaleType="fitCenter"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_email"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="16sp"
android:textColor="@color/primaryTextColor"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/icon_email"
android:layout_centerVertical="true"
android:text="@string/about_option_email"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:paddingTop="16dp"
android:clickable="true"
android:focusable="true"
android:background="@drawable/bg_ripple"
android:layout_marginBottom="16dp"
android:paddingStart="16dp"
android:paddingEnd="8dp">
<ImageView
android:id="@+id/icon_website"
android:layout_height="22dp"
android:layout_width="22dp"
android:scaleType="fitCenter"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_website"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="16sp"
android:textColor="@color/primaryTextColor"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/icon_website"
android:layout_centerVertical="true"
android:text="@string/about_option_website"/>
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Developers"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp"
android:textStyle="bold"
android:textSize="16sp"/>
<View
android:background="?android:attr/dividerVertical"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="16dp"
android:text="\u2022 Akash Yadav\n\u2022 Marvin Stelter"
android:layout_marginBottom="16dp"
android:textSize="14sp"
android:textColor="@color/secondaryTextColor_lighter"
android:autoLink="all"
android:linksClickable="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open source licenses"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp"
android:textStyle="bold"
android:textSize="16sp"/>
<View
android:background="?android:attr/dividerVertical"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="16dp"
android:textColor="@color/secondaryTextColor_lighter"
android:text="AndroidIDE uses open source libraries. You can find the source and the license of the libraries used by clicking on below links."
android:layout_marginBottom="4dp"
android:textSize="14sp"
android:autoLink="all"
android:linksClickable="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:id="@+id/licenses"
android:textColor="@color/secondaryTextColor_lighter"
android:textSize="14sp"/>
<TextView
android:id="@+id/footer_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginBottom="16dp"
android:textColor="@color/secondaryTextColor"/>
</LinearLayout>
@@ -2,6 +2,8 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="RelativeOverlap"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list_container">
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="Overdraw"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -14,7 +16,8 @@
android:id="@+id/diagnostics"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingStart="16dp"/>
android:paddingStart="16dp"
android:paddingEnd="16dp"/>
</LinearLayout>
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="UnusedAttribute"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -8,7 +10,7 @@
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:gravity="top|left"
android:gravity="top|start"
android:clickable="true"
android:focusable="true"
android:descendantFocusability="blocksDescendants"
@@ -25,7 +27,6 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Text"
android:textSize="15sp"
android:id="@+id/title"
android:textColor="@color/primaryTextColor"/>
@@ -2,6 +2,7 @@
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/primaryLightColor"
@@ -74,6 +75,7 @@
</com.google.android.material.card.MaterialCardView>
<ImageView
tools:ignore="UnusedAttribute"
app:srcCompat="@drawable/ic_file_delete"
android:layout_width="50dp"
android:layout_height="match_parent"
@@ -97,6 +99,7 @@
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:visibility="gone"
android:enabled="false"
android:id="@+id/confirmDeleteContainer">
+40 -63
View File
@@ -1,76 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 2020-2021 Rosemoe
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
<LinearLayout
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
android:layout_width="wrap_content"
android:fillViewport="true">
<HorizontalScrollView
<LinearLayout
android:layout_height="match_parent"
android:layout_width="wrap_content">
android:layout_width="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<LinearLayout
android:layout_height="match_parent"
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
android:text="@string/selectAll"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_select_all"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/selectAll"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_select_all"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/copy"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_copy"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/copy"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_copy"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/paste"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_paste"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/paste"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_paste"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/cut"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_cut"/>
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/cut"
android:textColor="#FF000000"
android:textSize="12sp"
android:id="@+id/panel_btn_cut"/>
</LinearLayout>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</HorizontalScrollView>
+16 -7
View File
@@ -1,4 +1,12 @@
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="msg_about_license_source">Source and License: %s</string>
<string name="msg_about_licensed_under">Licensed under %s</string>
<string name="msg_about_no_licenses">Failed to load licenses</string>
<string name="about_option_email">Email</string>
<string name="about_option_website">Website</string>
<string name="about_footer_alternate">AndroidIDE v\u2022 %s</string>
<string name="about_footer">AndroidIDE %1$s for %2$s</string>
<string name="about_subtitle">Simply, an IDE for Android</string>
<string name="view_diags">Diagnostics</string>
<string name="diagnostic_position">Start: %s, %s End: %s, %s</string>
<string name="diagnostic_error">ERROR</string>
@@ -11,11 +19,11 @@
<string name="msg_failed_get_changelog">Failed to read changelog!</string>
<string name="pref_changelog">Changelog</string>
<string name="pref_changelog_summary">What\'s new in this version?</string>
<string name="msg_getting_daemom_status">Getting Daemon status, please wait...</string>
<string name="msg_indexing_success">Indexing success! Starting services...</string>
<string name="msg_getting_daemom_status">Getting Daemon status, please wait&#8230;</string>
<string name="msg_indexing_success">Indexing success! Starting services&#8230;</string>
<string name="msg_indexing_failed">Index failed!</string>
<string name="msg_indexing">Indexing: %s</string>
<string name="msg_daemons_force_stopping">Gradle build process is running. Killing daemons...</string>
<string name="msg_daemons_force_stopping">Gradle build process is running. Killing daemons&#8230;</string>
<string name="msg_daemons_stopped">Gradle Daemons Stopped</string>
<string name="recreate_completion_services">Recreate services</string>
<string name="gradle_daemon_status">Gradle daemon status</string>
@@ -57,6 +65,7 @@
<string name="msg_install_gradle">Currently installed gradle version will be DELETE PEEMANENTLY!\n\nPlease enter full path of the zip file which contains Gradle distribution.</string>
<string name="reset">Reset</string>
<string name="title_change_text_size">Editor font size</string>
<string name="idepref_about_title">About AndroidIDE</string>
<string name="idepref_build_clearCache_title">Clear Gradle caches</string>
<string name="idepref_build_clearCache_summary">Clear Gradle caches directory. This will delete all dependencies downloaded by Gradle. Required files will be downloaded again in next build.</string>
<string name="idepref_build_choosegradle_title">Choose Gradle version</string>
@@ -126,7 +135,7 @@
<string name="msg_file_exists">File already exists!</string>
<string name="msg_invalid_name">Invalid Name!</string>
<string name="text_create">Create</string>
<string name="msg_can_contain_slashes">You can use forward slashes (\'/\') to define a relative path to this folder. This will create directories if they do not already exist and will save time in creating multiple directories.</string>
<string name="msg_can_contain_slashes">If the path contains File separator (\'/\'), then the required (parent) directories will be created if they don\'t exist.</string>
<string name="folder_name">Folder Name</string>
<string name="file_name">File Name</string>
<string name="new_name">New name</string>
@@ -191,7 +200,7 @@
<string name="template_empty">Empty project</string>
<string name="template_navigation_drawer">Navigation drawer project</string>
<string name="unknown_type">Unknown type</string>
<string name="app_name">Android IDE</string>
<string name="app_name">AndroidIDE</string>
<string name="build">Build</string>
<string name="build_debug">assembleDebug</string>
<string name="build_output">Build output</string>
@@ -232,7 +241,7 @@
<string name="nothing_here">Nothing here &#8230;</string>
<item name="paste" type="string">Paste</item>
<item name="copy" type="string">Copy</item>
<item name="copy" type="string" tools:override="true">Copy</item>
<item name="selectAll" type="string" formatted="true">Select All</item>
<item name="saveToProject" type="string" translatable="false" >Project</item>
<item name="cut" type="string">Cut</item>
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<Transition
app:constraintSetEnd="@+id/end"
app:constraintSetStart="@+id/start"
app:duration="500">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="@id/about_scroller"/>
</Transition>
<ConstraintSet
android:id="@+id/start">
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/icon_anchor"
android:layout_width="0dp"
android:layout_height="200dp"/>
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_anchor"
android:id="@+id/icon_container"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="-28dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"/>
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_container"
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"/>
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"/>
<Constraint
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle"
android:id="@+id/about_scroller"/>
</ConstraintSet>
<ConstraintSet
android:id="@+id/end">
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/icon_anchor"
android:layout_width="0dp"
android:layout_height="200dp"/>
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_anchor"
android:id="@+id/icon_container"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="-28dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"/>
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_container"
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Constraint
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Constraint
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle"
android:id="@+id/about_scroller"/>
</ConstraintSet>
</MotionScene>
-1
View File
@@ -1 +0,0 @@
/build
-33
View File
@@ -1,33 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdk
buildToolsVersion rootProject.ext.buildTools
defaultConfig {
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildFeatures {
viewBinding true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
-17
View File
@@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:/tools/adt-bundle-windows-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itsaky.androidide.javadoc" >
</manifest>
@@ -1,90 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc;
import static java.util.stream.Collectors.toList;
import java.util.Collections;
import java.util.List;
import com.itsaky.androidide.javadoc.tags.Tag;
/**
* This Javadoc object holds the parsed information.
*
* @author chhorz
*
*/
public class JavaDoc {
private String summary;
private String description;
private List<Tag> tags;
public JavaDoc(final String summary, final String description, final List<Tag> tags) {
this.summary = summary;
this.description = description;
this.tags = tags;
}
/**
* The summary is either defined by the new tag {(at)summary ...} or the first sentence of the textual description.
*
* @return the summary of the textual description
*/
public String getSummary() {
return summary;
}
/**
* The Javadoc description is the whole text until the first tag.
*
* @return the complete textual description
*/
public String getDescription() {
return description;
}
/**
* This method returns all parsed {@link Tag}s
*
* @return a list of all tags
*/
public List<Tag> getTags() {
return tags == null ? Collections.emptyList() : tags;
}
/**
* This method returns a list of all tags from the given class.
*
* @param tagClass a class to filter the output
* @return a list of tags from the given class
*/
public <T extends Tag> List<T> getTags(final Class<T> tagClass) {
return tags == null ? Collections.emptyList() : tags.stream()
.filter(tagClass::isInstance)
.map(tagClass::cast)
.collect(toList());
}
@Override
public String toString() {
return String.format("JavaDoc [summary=%s, description=%s, tags=%s]", summary, description, tags);
}
}
@@ -1,160 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.concat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import com.itsaky.androidide.javadoc.exception.DuplicateTagException;
import com.itsaky.androidide.javadoc.tags.Tag;
/**
*
* @author chhorz
*
*/
public final class JavaDocParser {
private List<Tag> tags = new ArrayList<>();
private Map<String, String> replacements = new HashMap<>();
public JavaDoc parse(final String javaDocString) {
String summary = "";
String description = "";
List<Tag> parsedTags = new ArrayList<>();
if (javaDocString != null && !javaDocString.isEmpty()) {
final String rawDescription = parseDescription(javaDocString);
summary = performReplacements(parseSummary(rawDescription));
description = performReplacements(rawDescription);
parsedTags = parseTags(javaDocString);
}
return new JavaDoc(summary, description, parsedTags);
}
private String parseSummary(final String description) {
if (description.isEmpty()) {
return "";
} else if (description.contains("@summary")) {
Pattern summaryPattern = Pattern.compile("\\{@summary ([^{}]+)}([\\s.,:;-])?");
Matcher summaryMatcher = summaryPattern.matcher(description);
if (summaryMatcher.find()) {
return summaryMatcher.group(1);
} else {
return "";
}
} else {
if (description.contains(".")) {
return description.substring(0, description.indexOf('.') + 1);
} else {
return description;
}
}
}
private String parseDescription(final String javaDocString) {
String[] lines = javaDocString.split("\n");
StringBuilder stringBuilder = new StringBuilder();
for (String line : lines) {
if (line.trim().startsWith("@")) {
break;
}
stringBuilder.append(line).append("\n");
}
return stringBuilder.toString().trim();
}
private List<Tag> parseTags(final String javaDocString) {
List<Tag> tagList = new ArrayList<>();
Stream<String> tagNamesStream = tags.stream()
.map(tag -> tag.getTagName())
.map(tag -> String.format("@%s", tag));
String allTagNames = concat(tagNamesStream, Stream.of("[^{]@\\S+"))
.collect(joining("|", "(?=", "|$)"));
for (Tag tag : tags) {
Pattern pattern = Pattern.compile(tag.createPattern(allTagNames), Pattern.DOTALL);
Matcher matcher = pattern.matcher(javaDocString);
int start = 0;
while (matcher.find(start)) {
Tag currentTag;
try {
currentTag = tag.getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
currentTag = tag;
e.printStackTrace();
}
for (String segmentName : tag.getSegmentNames()) {
currentTag.putValue(segmentName, performReplacements(matcher.group(segmentName)));
}
tagList.add(currentTag);
start = matcher.end();
}
}
return tagList;
}
private String performReplacements(final String input) {
String convertedString = input;
for (Entry<String, String> replacement : replacements.entrySet()) {
convertedString = convertedString.replaceAll(replacement.getKey(), replacement.getValue());
}
return convertedString.trim();
}
void addReplacement(final String regex, final String replacement){
Objects.requireNonNull(regex, "The given regex must not be null!");
Objects.requireNonNull(replacement, "The given replacement must not be null!");
if (regex.isEmpty()) {
throw new IllegalArgumentException("The given regex must not be empty!");
}
replacements.put(regex, replacement);
}
void addTag(final Tag tag) {
Objects.requireNonNull(tag, "The given tag must not be null!");
if (tags.stream().anyMatch(t -> t.getClass().equals(tag.getClass()))){
throw new DuplicateTagException(tag);
}
tags.add(tag);
}
}
@@ -1,93 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc;
import java.util.stream.Stream;
import com.itsaky.androidide.javadoc.tags.*;
/**
*
* @author chhorz
*
*/
public class JavaDocParserBuilder {
private static final String BASE_INLINE_PATTERN = "\\{@%s ([^\\{\\}]+)\\}([\\s.,:;-])?";
private static final String INLINE_SUMMARY_PATTERN = String.format(BASE_INLINE_PATTERN, "summary");
private static final String INLINE_CODE_PATTERN = String.format(BASE_INLINE_PATTERN, "code");
private static final String INLINE_LINK_PATTERN = String.format(BASE_INLINE_PATTERN, "link");
private static final String INLINE_LINKPLAIN_PATTERN = String.format(BASE_INLINE_PATTERN, "linkplain");
private static final String INLINE_LITERAL_PATTERN = String.format(BASE_INLINE_PATTERN, "literal");
private static final String INLINE_VALUE_PATTERN = String.format(BASE_INLINE_PATTERN, "value");
private JavaDocParser javaDocParser;
private JavaDocParserBuilder() {
this.javaDocParser = new JavaDocParser();
Stream.of(new AuthorTag(),
new CategoryTag(),
new DeprecatedTag(),
new ExceptionTag(),
new ParamTag(),
new ReturnTag(),
new SeeTag(),
new SinceTag(),
new ThrowsTag(),
new VersionTag())
.forEach(javaDocParser::addTag);
}
public static JavaDocParserBuilder withBasicTags() {
return new JavaDocParserBuilder();
}
public <T extends Tag> JavaDocParserBuilder withCustomTag(final T tag) {
javaDocParser.addTag(tag);
return this;
}
public JavaDocParserBuilder withOutputType(final OutputType outputType) {
javaDocParser.addReplacement(INLINE_SUMMARY_PATTERN, "$1$2");
if (OutputType.ASCIIDOC.equals(outputType) || OutputType.MARKDOWN.equals(outputType)) {
javaDocParser.addReplacement(INLINE_CODE_PATTERN, "`$1`$2");
javaDocParser.addReplacement(INLINE_LINK_PATTERN, "$1$2");
javaDocParser.addReplacement(INLINE_LINKPLAIN_PATTERN, "$1$2");
javaDocParser.addReplacement(INLINE_LITERAL_PATTERN, "_$1_$2");
javaDocParser.addReplacement(INLINE_VALUE_PATTERN, "`$1`$2");
} else if (OutputType.HTML.equals(outputType)) {
javaDocParser.addReplacement(INLINE_CODE_PATTERN, "<code>$1</code>$2");
javaDocParser.addReplacement(INLINE_LINK_PATTERN, "$1$2");
javaDocParser.addReplacement(INLINE_LINKPLAIN_PATTERN, "$1$2");
javaDocParser.addReplacement(INLINE_LITERAL_PATTERN, "<i>$1</i>$2");
javaDocParser.addReplacement(INLINE_VALUE_PATTERN, "<pre>$1</pre>$2");
}
return this;
}
public JavaDocParserBuilder withReplacement(final String regex, final String replacement) {
javaDocParser.addReplacement(regex, replacement);
return this;
}
public JavaDocParser build() {
return javaDocParser;
}
}
@@ -1,34 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc;
/**
*
* @author chhorz
*
*/
public enum OutputType {
ASCIIDOC,
HTML,
MARKDOWN,
PLAIN;
}
@@ -1,36 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.exception;
import com.itsaky.androidide.javadoc.tags.Tag;
/**
* A exception that is thrown if more than one tags of one type should be registered within one parser.
*
* @author chhorz
*
*/
public class DuplicateTagException extends RuntimeException {
public static final long serialVersionUID = 1l;
public DuplicateTagException(final Tag tag){
super(String.format("The parser contains a tag '@%s'.", tag.getTagName()));
}
}
@@ -1,40 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDCBAHA
*
* @author chhorz
*
*/
public class AuthorTag extends StructuredTag {
private static final String TAG_NAME = "author";
private static final String NAME_TEXT = "nameText";
public AuthorTag() {
super(TAG_NAME, NAME_TEXT);
}
public String getAuthorName() {
return getValues().get(NAME_TEXT);
}
}
@@ -1,39 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
*
* @author chhorz
*
*/
public class CategoryTag extends StructuredTag {
private static final String TAG_NAME = "category";
private static final String CATEGORY_NAME = "categoryName";
public CategoryTag() {
super(TAG_NAME, CATEGORY_NAME);
}
public String getCategoryName() {
return getValues().get(CATEGORY_NAME);
}
}
@@ -1,40 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#deprecated
*
* @author chhorz
*
*/
public class DeprecatedTag extends StructuredTag {
private static final String TAG_NAME = "deprecated";
private static final String DEPRECATED_TEXT = "deprecatedText";
public DeprecatedTag() {
super(TAG_NAME, DEPRECATED_TEXT);
}
public String getDeprecatedNote() {
return getValues().get(DEPRECATED_TEXT);
}
}
@@ -1,45 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDCEAHH
*
* @author chhorz
*
*/
public class ExceptionTag extends StructuredTag {
private static final String TAG_NAME = "exception";
private static final String CLASS_NAME = "className";
private static final String DESCRIPTION = "description";
public ExceptionTag() {
super(TAG_NAME, CLASS_NAME, DESCRIPTION);
}
public String getClassName() {
return getValues().get(CLASS_NAME);
}
public String getDescription() {
return getValues().get(DESCRIPTION);
}
}
@@ -1,45 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDHJECF
*
* @author chhorz
*
*/
public class ParamTag extends StructuredTag {
private static final String TAG_NAME = "param";
private static final String PARAMETER_NAME = "parameterName";
private static final String DESCRIPTION = "description";
public ParamTag() {
super(TAG_NAME, PARAMETER_NAME, DESCRIPTION);
}
public String getParamName() {
return getValues().get(PARAMETER_NAME);
}
public String getParamDescription() {
return getValues().get(DESCRIPTION);
}
}
@@ -1,50 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* A PatternTag can be used to define a custom {@link java.util.regex.Pattern}. For this free kind of tag, more methods have to be implemented.
*
* @author chhorz
*
*/
public abstract class PatternTag extends Tag {
private String name;
private String pattern;
public PatternTag(final String name, final String pattern) {
this.name = name;
this.pattern = pattern;
}
public String getTagName() {
return name == null ? "" : name;
}
@Override
public String createPattern(final String allTagNames) {
return "@" + name + pattern + "\\s*" + allTagNames;
}
@Override
public String toString() {
return String.format("Tag [name=%s, pattern=%s]", name, pattern);
}
}
@@ -1,40 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDCDBGG
*
* @author chhorz
*
*/
public class ReturnTag extends StructuredTag {
private static final String TAG_NAME = "return";
private static final String DESCRIPTION = "description";
public ReturnTag() {
super(TAG_NAME, DESCRIPTION);
}
public String getDesrcription() {
return getValues().get(DESCRIPTION);
}
}
@@ -1,40 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDDIEDI
*
* @author chhorz
*
*/
public class SeeTag extends StructuredTag {
private static final String TAG_NAME = "see";
private static final String REFERENCE = "reference";
public SeeTag() {
super(TAG_NAME, REFERENCE);
}
public String getReference() {
return getValues().get(REFERENCE);
}
}
@@ -1,40 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDHGJGD
*
* @author chhorz
*
*/
public class SinceTag extends StructuredTag {
private static final String TAG_NAME = "since";
private static final String SINCE_TEXT = "sinceText";
public SinceTag() {
super(TAG_NAME, SINCE_TEXT);
}
public String getSinceText() {
return getValues().get(SINCE_TEXT);
}
}
@@ -1,77 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
*
* @author chhorz
*
*/
public abstract class StructuredTag extends Tag {
private String name;
private List<String> segmentNames;
private TreeMap<String, String> values = new TreeMap<>();
public StructuredTag(final String name, final String... segmentNames) {
this.name = name;
this.segmentNames = Arrays.asList(segmentNames);
for (String segmentName : segmentNames) {
values.put(segmentName, "");
}
}
public String getTagName() {
return name == null ? "" : name;
}
public List<String> getSegmentNames() {
return segmentNames == null ? Collections.emptyList() : segmentNames;
}
public Map<String, String> getValues() {
return values == null ? new HashMap<String, String>() : values;
}
public void putValue(final String segmentName, final String segmentValue) {
if (values.containsKey(segmentName)) {
values.put(segmentName, segmentValue != null ? segmentValue : "");
}
}
public String createPattern(final String allTagNames) {
StringBuilder sb = new StringBuilder();
for (String segmentName : getSegmentNames()) {
sb.append("\\s+?(?<" + segmentName + ">.+?)");
}
return "@" + name + sb.toString() + "\\s*" + allTagNames;
}
@Override
public String toString() {
return String.format("Tag [name=%s, values=%s]", name, values);
}
}
@@ -1,57 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
import java.util.List;
/**
* Base class for all internal Javadoc tags.
*
* @author chhorz
*
*/
public abstract class Tag {
/**
*
*
* @return the Javadoc tag name
*/
public abstract String getTagName();
/**
*
* @return all names of segments that can be read
*/
public abstract List<String> getSegmentNames();
/**
*
* @param segmentName the segment name for which the value should be saved
* @param value the value that was parsed for the segment
*/
public abstract void putValue(final String segmentName, final String value);
/**
*
* @param allTagNames the list of all patterns will be calculated on the fly and describes the end of a sinlge tag
* @return the complete pattern string for this tag
*/
public abstract String createPattern(final String allTagNames);
}
@@ -1,45 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDCHAHD
*
* @author chhorz
*
*/
public class ThrowsTag extends StructuredTag {
private static final String TAG_NAME = "throws";
private static final String CLASS_NAME = "className";
private static final String DESCRIPTION = "description";
public ThrowsTag() {
super(TAG_NAME, CLASS_NAME, DESCRIPTION);
}
public String getClassName() {
return getValues().get(CLASS_NAME);
}
public String getDescription() {
return getValues().get(DESCRIPTION);
}
}
@@ -1,40 +0,0 @@
/**
*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.itsaky.androidide.javadoc.tags;
/**
* https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDCHBAE
*
* @author chhorz
*
*/
public class VersionTag extends StructuredTag {
private static final String TAG_NAME = "version";
private static final String VERSION_TEXT = "versionText";
public VersionTag() {
super(TAG_NAME, VERSION_TEXT);
}
public String getVersionText() {
return getValues().get(VERSION_TEXT);
}
}
-3
View File
@@ -1,8 +1,5 @@
include ':app'
include ':treeview'
include ':spinkit'
include ':slidr'
include ':javadocparser'
include ':lsp'
rootProject.name = "Android IDE"
-1
View File
@@ -1 +0,0 @@
/build
-29
View File
@@ -1,29 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdk
buildToolsVersion rootProject.ext.buildTools
defaultConfig {
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
}
-17
View File
@@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ybq/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-4
View File
@@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.r0adkll.slidr">
<application />
</manifest>
@@ -1,67 +0,0 @@
package com.r0adkll.slidr;
import android.animation.ArgbEvaluator;
import android.app.Activity;
import android.os.Build;
import androidx.annotation.ColorInt;
import com.r0adkll.slidr.widget.SliderPanel;
class ColorPanelSlideListener implements SliderPanel.OnPanelSlideListener {
private final Activity activity;
private final int primaryColor;
private final int secondaryColor;
private final ArgbEvaluator evaluator = new ArgbEvaluator();
ColorPanelSlideListener(Activity activity, @ColorInt int primaryColor, @ColorInt int secondaryColor) {
this.activity = activity;
this.primaryColor = primaryColor;
this.secondaryColor = secondaryColor;
}
@Override
public void onStateChanged(int state) {
// Unused.
}
@Override
public void onClosed() {
activity.finish();
activity.overridePendingTransition(0, 0);
}
@Override
public void onOpened() {
// Unused.
}
@Override
public void onSlideChange(float percent) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && areColorsValid()){
int newColor = (int) evaluator.evaluate(percent, getPrimaryColor(), getSecondaryColor());
activity.getWindow().setStatusBarColor(newColor);
}
}
protected int getPrimaryColor() {
return primaryColor;
}
protected int getSecondaryColor() {
return secondaryColor;
}
protected boolean areColorsValid() {
return getPrimaryColor() != -1 && getSecondaryColor() != -1;
}
}
@@ -1,66 +0,0 @@
package com.r0adkll.slidr;
import android.app.Activity;
import androidx.annotation.NonNull;
import com.r0adkll.slidr.model.SlidrConfig;
class ConfigPanelSlideListener extends ColorPanelSlideListener {
private final SlidrConfig config;
ConfigPanelSlideListener(@NonNull Activity activity, @NonNull SlidrConfig config) {
super(activity, -1, -1);
this.config = config;
}
@Override
public void onStateChanged(int state) {
if(config.getListener() != null){
config.getListener().onSlideStateChanged(state);
}
}
@Override
public void onClosed() {
if(config.getListener() != null){
if(config.getListener().onSlideClosed()) {
return;
}
}
super.onClosed();
}
@Override
public void onOpened() {
if(config.getListener() != null){
config.getListener().onSlideOpened();
}
}
@Override
public void onSlideChange(float percent) {
super.onSlideChange(percent);
if(config.getListener() != null){
config.getListener().onSlideChange(percent);
}
}
@Override
protected int getPrimaryColor() {
return config.getPrimaryColor();
}
@Override
protected int getSecondaryColor() {
return config.getSecondaryColor();
}
}
@@ -1,66 +0,0 @@
package com.r0adkll.slidr;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import android.view.View;
import com.r0adkll.slidr.model.SlidrConfig;
import com.r0adkll.slidr.widget.SliderPanel;
class FragmentPanelSlideListener implements SliderPanel.OnPanelSlideListener {
private final View view;
private final SlidrConfig config;
FragmentPanelSlideListener(@NonNull View view, @NonNull SlidrConfig config) {
this.view = view;
this.config = config;
}
@Override
public void onStateChanged(int state) {
if (config.getListener() != null) {
config.getListener().onSlideStateChanged(state);
}
}
@Override
public void onClosed() {
if (config.getListener() != null) {
if(config.getListener().onSlideClosed()) {
return;
}
}
// Ensure that we are attached to a FragmentActivity
if (view.getContext() instanceof FragmentActivity) {
final FragmentActivity activity = (FragmentActivity) view.getContext();
if (activity.getSupportFragmentManager().getBackStackEntryCount() == 0) {
activity.finish();
activity.overridePendingTransition(0, 0);
} else {
activity.getSupportFragmentManager().popBackStack();
}
}
}
@Override
public void onOpened() {
if (config.getListener() != null) {
config.getListener().onSlideOpened();
}
}
@Override
public void onSlideChange(float percent) {
if (config.getListener() != null) {
config.getListener().onSlideChange(percent);
}
}
}
@@ -1,132 +0,0 @@
package com.r0adkll.slidr;
import android.app.Activity;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import com.r0adkll.slidr.model.SlidrConfig;
import com.r0adkll.slidr.model.SlidrInterface;
import com.r0adkll.slidr.widget.SliderPanel;
/**
* This attacher class is used to attach the sliding mechanism to any {@link android.app.Activity}
* that lets the user slide (or swipe) the activity away as a form of back or up action. The action
* causes {@link android.app.Activity#finish()} to be called.
*/
public final class Slidr {
/**
* Attach a slideable mechanism to an activity that adds the slide to dismiss functionality
*
* @param activity the activity to attach the slider to
* @return a {@link com.r0adkll.slidr.model.SlidrInterface} that allows
* the user to lock/unlock the sliding mechanism for whatever purpose.
*/
@NonNull
public static SlidrInterface attach(@NonNull Activity activity) {
return attach(activity, -1, -1);
}
/**
* Attach a slideable mechanism to an activity that adds the slide to dismiss functionality
* and allows for the statusbar to transition between colors
*
* @param activity the activity to attach the slider to
* @param statusBarColor1 the primaryDark status bar color of the interface that this will slide back to
* @param statusBarColor2 the primaryDark status bar color of the activity this is attaching to that will transition
* back to the statusBarColor1 color
* @return a {@link com.r0adkll.slidr.model.SlidrInterface} that allows
* the user to lock/unlock the sliding mechanism for whatever purpose.
*/
@NonNull
public static SlidrInterface attach(@NonNull Activity activity, @ColorInt int statusBarColor1,
@ColorInt int statusBarColor2) {
// Setup the slider panel and attach it to the decor
final SliderPanel panel = attachSliderPanel(activity, null);
// Set the panel slide listener for when it becomes closed or opened
panel.setOnPanelSlideListener(new ColorPanelSlideListener(activity, statusBarColor1, statusBarColor2));
// Return the lock interface
return panel.getDefaultInterface();
}
/**
* Attach a slider mechanism to an activity based on the passed {@link com.r0adkll.slidr.model.SlidrConfig}
*
* @param activity the activity to attach the slider to
* @param config the slider configuration to make
* @return a {@link com.r0adkll.slidr.model.SlidrInterface} that allows
* the user to lock/unlock the sliding mechanism for whatever purpose.
*/
@NonNull
public static SlidrInterface attach(@NonNull Activity activity, @NonNull SlidrConfig config) {
// Setup the slider panel and attach it to the decor
final SliderPanel panel = attachSliderPanel(activity, config);
// Set the panel slide listener for when it becomes closed or opened
panel.setOnPanelSlideListener(new ConfigPanelSlideListener(activity, config));
// Return the lock interface
return panel.getDefaultInterface();
}
/**
* Attach a new {@link SliderPanel} to the root of the activity's content
*/
@NonNull
private static SliderPanel attachSliderPanel(@NonNull Activity activity, @NonNull SlidrConfig config) {
// Hijack the decorview
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
View oldScreen = decorView.getChildAt(0);
decorView.removeViewAt(0);
// Setup the slider panel and attach it to the decor
SliderPanel panel = new SliderPanel(activity, oldScreen, config);
panel.setId(R.id.slidable_panel);
oldScreen.setId(R.id.slidable_content);
panel.addView(oldScreen);
decorView.addView(panel, 0);
return panel;
}
/**
* Attach a slider mechanism to a fragment view replacing an internal view
*
* @param oldScreen the view within a fragment to replace
* @param config the slider configuration to attach with
* @return a {@link com.r0adkll.slidr.model.SlidrInterface} that allows
* the user to lock/unlock the sliding mechanism for whatever purpose.
*/
@NonNull
public static SlidrInterface replace(@NonNull final View oldScreen, @NonNull final SlidrConfig config) {
ViewGroup parent = (ViewGroup) oldScreen.getParent();
ViewGroup.LayoutParams params = oldScreen.getLayoutParams();
parent.removeView(oldScreen);
// Setup the slider panel and attach it
final SliderPanel panel = new SliderPanel(oldScreen.getContext(), oldScreen, config);
panel.setId(R.id.slidable_panel);
oldScreen.setId(R.id.slidable_content);
panel.addView(oldScreen);
parent.addView(panel, 0, params);
// Set the panel slide listener for when it becomes closed or opened
panel.setOnPanelSlideListener(new FragmentPanelSlideListener(oldScreen, config));
// Return the lock interface
return panel.getDefaultInterface();
}
}
@@ -1,318 +0,0 @@
package com.r0adkll.slidr.model;
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.customview.widget.ViewDragHelper;
/**
* This class contains the configuration information for all the options available in
* this library
*/
public class SlidrConfig {
private int colorPrimary = -1;
private int colorSecondary = -1;
private float touchSize = -1f;
private float sensitivity = 1f;
private int scrimColor = Color.BLACK;
private float scrimStartAlpha = 0.8f;
private float scrimEndAlpha = 0f;
private float velocityThreshold = 5f;
private float distanceThreshold = 0.25f;
private boolean edgeOnly = false;
private float edgeSize = 0.18f;
private SlidrPosition position = SlidrPosition.LEFT;
private SlidrListener listener;
private SlidrConfig() {
// Unused.
}
/***********************************************************************************************
*
* Getters
*
*/
/**
* Get the primary color that the slider will interpolate. That is this color is the color
* of the status bar of the Activity you are returning to
*
* @return the primary status bar color
*/
public int getPrimaryColor(){
return colorPrimary;
}
/**
* Get the secondary color that the slider will interpolatel That is the color of the Activity
* that you are making slidable
*
* @return the secondary status bar color
*/
public int getSecondaryColor(){
return colorSecondary;
}
/**
* Get the color of the background scrim
*
* @return the scrim color integer
*/
@ColorInt
public int getScrimColor(){
return scrimColor;
}
/**
* Get teh start alpha value for when the activity is not swiped at all
*
* @return the start alpha value (0.0 to 1.0)
*/
public float getScrimStartAlpha(){
return scrimStartAlpha;
}
/**
* Get the end alpha value for when the user almost swipes the activity off the screen
*
* @return the end alpha value (0.0 to 1.0)
*/
public float getScrimEndAlpha(){
return scrimEndAlpha;
}
/**
* Get the position of the slidable mechanism for this configuration. This is the position on
* the screen that the user can swipe the activity away from
*
* @return the slider position
*/
public SlidrPosition getPosition(){
return position;
}
/**
* Get the touch 'width' to be used in the gesture detection. This value should incorporate with
* the device's touch slop
*
* @return the touch area size
*/
public float getTouchSize(){
return touchSize;
}
/**
* Get the velocity threshold at which the slide action is completed regardless of offset
* distance of the drag
*
* @return the velocity threshold
*/
public float getVelocityThreshold(){
return velocityThreshold;
}
/**
* Get at what % of the screen is the minimum viable distance the activity has to be dragged
* in-order to be slinged off the screen
*
* @return the distant threshold as a percentage of the screen size (width or height)
*/
public float getDistanceThreshold(){
return distanceThreshold;
}
/**
* Get the touch sensitivity set in the {@link ViewDragHelper} when
* creating it.
*
* @return the touch sensitivity
*/
public float getSensitivity(){
return sensitivity;
}
/**
* Get the slidr listener set by the user to respond to certain events in the sliding
* mechanism.
*
* @return the slidr listener
*/
public SlidrListener getListener(){
return listener;
}
/**
* Has the user configured slidr to only catch at the edge of the screen ?
*
* @return true if is edge capture only
*/
public boolean isEdgeOnly() {
return edgeOnly;
}
/**
* Get the size of the edge field that is catchable
*
* @see #isEdgeOnly()
* @return the size of the edge that is grabable
*/
public float getEdgeSize(float size) {
return edgeSize * size;
}
/***********************************************************************************************
*
* Setters
*
*/
public void setColorPrimary(int colorPrimary) {
this.colorPrimary = colorPrimary;
}
public void setColorSecondary(int colorSecondary) {
this.colorSecondary = colorSecondary;
}
public void setTouchSize(float touchSize) {
this.touchSize = touchSize;
}
public void setSensitivity(float sensitivity) {
this.sensitivity = sensitivity;
}
public void setScrimColor(@ColorInt int scrimColor) {
this.scrimColor = scrimColor;
}
public void setScrimStartAlpha(float scrimStartAlpha) {
this.scrimStartAlpha = scrimStartAlpha;
}
public void setScrimEndAlpha(float scrimEndAlpha) {
this.scrimEndAlpha = scrimEndAlpha;
}
public void setVelocityThreshold(float velocityThreshold) {
this.velocityThreshold = velocityThreshold;
}
public void setDistanceThreshold(float distanceThreshold) {
this.distanceThreshold = distanceThreshold;
}
/**
* The Builder for this configuration class. This is the only way to create a
* configuration
*/
public static class Builder{
private SlidrConfig config;
public Builder(){
config = new SlidrConfig();
}
public Builder primaryColor(@ColorInt int color){
config.colorPrimary = color;
return this;
}
public Builder secondaryColor(@ColorInt int color){
config.colorSecondary = color;
return this;
}
public Builder position(SlidrPosition position){
config.position = position;
return this;
}
public Builder touchSize(float size){
config.touchSize = size;
return this;
}
public Builder sensitivity(float sensitivity){
config.sensitivity = sensitivity;
return this;
}
public Builder scrimColor(@ColorInt int color){
config.scrimColor = color;
return this;
}
public Builder scrimStartAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha){
config.scrimStartAlpha = alpha;
return this;
}
public Builder scrimEndAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha){
config.scrimEndAlpha = alpha;
return this;
}
public Builder velocityThreshold(float threshold){
config.velocityThreshold = threshold;
return this;
}
public Builder distanceThreshold(@FloatRange(from = .1f, to = .9f) float threshold){
config.distanceThreshold = threshold;
return this;
}
public Builder edge(boolean flag){
config.edgeOnly = flag;
return this;
}
public Builder edgeSize(@FloatRange(from = 0f, to = 1f) float edgeSize){
config.edgeSize = edgeSize;
return this;
}
public Builder listener(SlidrListener listener){
config.listener = listener;
return this;
}
public SlidrConfig build(){
return config;
}
}
}
@@ -1,8 +0,0 @@
package com.r0adkll.slidr.model;
public interface SlidrInterface {
void lock();
void unlock();
}
@@ -1,31 +0,0 @@
package com.r0adkll.slidr.model;
import androidx.customview.widget.ViewDragHelper;
/**
* This listener interface is for receiving events from the sliding panel such as state changes
* and slide progress
*/
public interface SlidrListener {
/**
* This is called when the {@link ViewDragHelper} calls it's
* state change callback.
*
* @see ViewDragHelper#STATE_IDLE
* @see ViewDragHelper#STATE_DRAGGING
* @see ViewDragHelper#STATE_SETTLING
*
* @param state the {@link ViewDragHelper} state
*/
void onSlideStateChanged(int state);
void onSlideChange(float percent);
void onSlideOpened();
/**
* @return <code>true</code> than event was processed in the callback.
*/
boolean onSlideClosed();
}
@@ -1,22 +0,0 @@
package com.r0adkll.slidr.model;
public class SlidrListenerAdapter implements SlidrListener {
@Override
public void onSlideStateChanged(int state) {
}
@Override
public void onSlideChange(float percent) {
}
@Override
public void onSlideOpened() {
}
@Override
public boolean onSlideClosed() {
return false;
}
}
@@ -1,12 +0,0 @@
package com.r0adkll.slidr.model;
public enum SlidrPosition {
LEFT,
RIGHT,
TOP,
BOTTOM,
VERTICAL,
HORIZONTAL
}
File diff suppressed because it is too large Load Diff
@@ -1,124 +0,0 @@
package com.r0adkll.slidr.widget;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import androidx.annotation.NonNull;
import android.view.View;
import com.r0adkll.slidr.model.SlidrPosition;
final class ScrimRenderer {
private final View rootView;
private final View decorView;
private final Rect dirtyRect;
ScrimRenderer(@NonNull View rootView, @NonNull View decorView) {
this.rootView = rootView;
this.decorView = decorView;
dirtyRect = new Rect();
}
void render(Canvas canvas, SlidrPosition position, Paint paint) {
switch (position) {
case LEFT:
renderLeft(canvas, paint);
break;
case RIGHT:
renderRight(canvas, paint);
break;
case TOP:
renderTop(canvas, paint);
break;
case BOTTOM:
renderBottom(canvas, paint);
break;
case VERTICAL:
renderVertical(canvas, paint);
break;
case HORIZONTAL:
renderHorizontal(canvas, paint);
break;
}
}
Rect getDirtyRect(SlidrPosition position) {
switch (position) {
case LEFT:
dirtyRect.set(0, 0, decorView.getLeft(), rootView.getMeasuredHeight());
break;
case RIGHT:
dirtyRect.set(decorView.getRight(), 0, rootView.getMeasuredWidth(), rootView.getMeasuredHeight());
break;
case TOP:
dirtyRect.set(0, 0, rootView.getMeasuredWidth(), decorView.getTop());
break;
case BOTTOM:
dirtyRect.set(0, decorView.getBottom(), rootView.getMeasuredWidth(), rootView.getMeasuredHeight());
break;
case VERTICAL:
if (decorView.getTop() > 0) {
dirtyRect.set(0, 0, rootView.getMeasuredWidth(), decorView.getTop());
}
else {
dirtyRect.set(0, decorView.getBottom(), rootView.getMeasuredWidth(), rootView.getMeasuredHeight());
}
break;
case HORIZONTAL:
if (decorView.getLeft() > 0) {
dirtyRect.set(0, 0, decorView.getLeft(), rootView.getMeasuredHeight());
}
else {
dirtyRect.set(decorView.getRight(), 0, rootView.getMeasuredWidth(), rootView.getMeasuredHeight());
}
break;
}
return dirtyRect;
}
private void renderLeft(Canvas canvas, Paint paint) {
canvas.drawRect(0, 0, decorView.getLeft(), rootView.getMeasuredHeight(), paint);
}
private void renderRight(Canvas canvas, Paint paint) {
canvas.drawRect(decorView.getRight(), 0, rootView.getMeasuredWidth(), rootView.getMeasuredHeight(), paint);
}
private void renderTop(Canvas canvas, Paint paint) {
canvas.drawRect(0, 0, rootView.getMeasuredWidth(), decorView.getTop(), paint);
}
private void renderBottom(Canvas canvas, Paint paint) {
canvas.drawRect(0, decorView.getBottom(), rootView.getMeasuredWidth(), rootView.getMeasuredHeight(), paint);
}
private void renderVertical(Canvas canvas, Paint paint) {
if (decorView.getTop() > 0) {
renderTop(canvas, paint);
}
else {
renderBottom(canvas, paint);
}
}
private void renderHorizontal(Canvas canvas, Paint paint) {
if (decorView.getLeft() > 0) {
renderLeft(canvas, paint);
}
else {
renderRight(canvas, paint);
}
}
}
@@ -1,782 +0,0 @@
package com.r0adkll.slidr.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import androidx.core.view.ViewCompat;
import androidx.core.view.ViewGroupCompat;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.r0adkll.slidr.model.SlidrConfig;
import com.r0adkll.slidr.util.ViewDragHelper;
import com.r0adkll.slidr.model.SlidrInterface;
public class SliderPanel extends FrameLayout {
private static final int MIN_FLING_VELOCITY = 400; // dips per second
private int screenWidth;
private int screenHeight;
private View decorView;
private ViewDragHelper dragHelper;
private OnPanelSlideListener listener;
private Paint scrimPaint;
private ScrimRenderer scrimRenderer;
private boolean isLocked = false;
private boolean isEdgeTouched = false;
private int edgePosition;
private SlidrConfig config;
public SliderPanel(Context context) {
super(context);
}
public SliderPanel(Context context, View decorView, SlidrConfig config){
super(context);
this.decorView = decorView;
this.config = (config == null ? new SlidrConfig.Builder().build() : config);
init();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean interceptForDrag;
if(isLocked){
return false;
}
if(config.isEdgeOnly()) {
isEdgeTouched = canDragFromEdge(ev);
}
// Fix for pull request #13 and issue #12
try {
interceptForDrag = dragHelper.shouldInterceptTouchEvent(ev);
} catch (Exception e) {
interceptForDrag = false;
}
return interceptForDrag && !isLocked;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(isLocked){
return false;
}
try {
dragHelper.processTouchEvent(event);
}catch (IllegalArgumentException e){
return false;
}
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if(dragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
protected void onDraw(Canvas canvas) {
scrimRenderer.render(canvas, config.getPosition(), scrimPaint);
}
/**
* Set the panel slide listener that gets called based on slider changes
* @param listener callback implementation
*/
public void setOnPanelSlideListener(OnPanelSlideListener listener){
this.listener = listener;
}
/**
* Get the default {@link SlidrInterface} from which to control the panel with after attachment
*/
public SlidrInterface getDefaultInterface() {
return defaultSlidrInterface;
}
private final SlidrInterface defaultSlidrInterface = new SlidrInterface() {
@Override
public void lock() {
SliderPanel.this.lock();
}
@Override
public void unlock() {
SliderPanel.this.unlock();
}
};
/**
* The drag helper callback interface for the Left position
*/
private final ViewDragHelper.Callback leftCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
boolean edgeCase = !config.isEdgeOnly() || dragHelper.isEdgeTouched(edgePosition, pointerId);
return child.getId() == decorView.getId() && edgeCase;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return clamp(left, 0, screenWidth);
}
@Override
public int getViewHorizontalDragRange(View child) {
return screenWidth;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int left = releasedChild.getLeft();
int settleLeft = 0;
int leftThreshold = (int) (getWidth() * config.getDistanceThreshold());
boolean isVerticalSwiping = Math.abs(yvel) > config.getVelocityThreshold();
if(xvel > 0){
if(Math.abs(xvel) > config.getVelocityThreshold() && !isVerticalSwiping){
settleLeft = screenWidth;
}else if(left > leftThreshold){
settleLeft = screenWidth;
}
}else if(xvel == 0){
if(left > leftThreshold){
settleLeft = screenWidth;
}
}
dragHelper.settleCapturedViewAt(settleLeft, releasedChild.getTop());
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)left / (float) screenWidth);
if(listener != null) listener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(listener != null) listener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(decorView.getLeft() == 0){
// State Open
if(listener != null) listener.onOpened();
}else{
// State Closed
if(listener != null) listener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break;
}
}
};
/**
* The drag helper callbacks for dragging the slidr attachment from the right of the screen
*/
private final ViewDragHelper.Callback rightCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
boolean edgeCase = !config.isEdgeOnly() || dragHelper.isEdgeTouched(edgePosition, pointerId);
return child.getId() == decorView.getId() && edgeCase;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return clamp(left, -screenWidth, 0);
}
@Override
public int getViewHorizontalDragRange(View child) {
return screenWidth;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int left = releasedChild.getLeft();
int settleLeft = 0;
int leftThreshold = (int) (getWidth() * config.getDistanceThreshold());
boolean isVerticalSwiping = Math.abs(yvel) > config.getVelocityThreshold();
if(xvel < 0){
if(Math.abs(xvel) > config.getVelocityThreshold() && !isVerticalSwiping){
settleLeft = -screenWidth;
}else if(left < -leftThreshold){
settleLeft = -screenWidth;
}
}else if(xvel == 0){
if(left < -leftThreshold){
settleLeft = -screenWidth;
}
}
dragHelper.settleCapturedViewAt(settleLeft, releasedChild.getTop());
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)Math.abs(left) / (float) screenWidth);
if(listener != null) listener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(listener != null) listener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(decorView.getLeft() == 0){
// State Open
if(listener != null) listener.onOpened();
}else{
// State Closed
if(listener != null) listener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break;
}
}
};
/**
* The drag helper callbacks for dragging the slidr attachment from the top of the screen
*/
private final ViewDragHelper.Callback topCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child.getId() == decorView.getId() && (!config.isEdgeOnly() || isEdgeTouched);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return clamp(top, 0, screenHeight);
}
@Override
public int getViewVerticalDragRange(View child) {
return screenHeight;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int top = releasedChild.getTop();
int settleTop = 0;
int topThreshold = (int) (getHeight() * config.getDistanceThreshold());
boolean isSideSwiping = Math.abs(xvel) > config.getVelocityThreshold();
if(yvel > 0){
if(Math.abs(yvel) > config.getVelocityThreshold() && !isSideSwiping){
settleTop = screenHeight;
}else if(top > topThreshold){
settleTop = screenHeight;
}
}else if(yvel == 0){
if(top > topThreshold){
settleTop = screenHeight;
}
}
dragHelper.settleCapturedViewAt(releasedChild.getLeft(), settleTop);
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)Math.abs(top) / (float) screenHeight);
if(listener != null) listener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(listener != null) listener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(decorView.getTop() == 0){
// State Open
if(listener != null) listener.onOpened();
}else{
// State Closed
if(listener != null) listener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break;
}
}
};
/**
* The drag helper callbacks for dragging the slidr attachment from the bottom of hte screen
*/
private final ViewDragHelper.Callback bottomCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child.getId() == decorView.getId() && (!config.isEdgeOnly() || isEdgeTouched);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return clamp(top, -screenHeight, 0);
}
@Override
public int getViewVerticalDragRange(View child) {
return screenHeight;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int top = releasedChild.getTop();
int settleTop = 0;
int topThreshold = (int) (getHeight() * config.getDistanceThreshold());
boolean isSideSwiping = Math.abs(xvel) > config.getVelocityThreshold();
if(yvel < 0){
if(Math.abs(yvel) > config.getVelocityThreshold() && !isSideSwiping){
settleTop = -screenHeight;
}else if(top < -topThreshold){
settleTop = -screenHeight;
}
}else if(yvel == 0){
if(top < -topThreshold){
settleTop = -screenHeight;
}
}
dragHelper.settleCapturedViewAt(releasedChild.getLeft(), settleTop);
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)Math.abs(top) / (float) screenHeight);
if(listener != null) listener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(listener != null) listener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(decorView.getTop() == 0){
// State Open
if(listener != null) listener.onOpened();
}else{
// State Closed
if(listener != null) listener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break;
}
}
};
/**
* The drag helper callbacks for dragging the slidr attachment in both vertical directions
*/
private final ViewDragHelper.Callback verticalCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child.getId() == decorView.getId() && (!config.isEdgeOnly() || isEdgeTouched);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return clamp(top, -screenHeight, screenHeight);
}
@Override
public int getViewVerticalDragRange(View child) {
return screenHeight;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int top = releasedChild.getTop();
int settleTop = 0;
int topThreshold = (int) (getHeight() * config.getDistanceThreshold());
boolean isSideSwiping = Math.abs(xvel) > config.getVelocityThreshold();
if(yvel > 0){
// Being slinged down
if(Math.abs(yvel) > config.getVelocityThreshold() && !isSideSwiping){
settleTop = screenHeight;
}else if(top > topThreshold){
settleTop = screenHeight;
}
}else if(yvel < 0){
// Being slinged up
if(Math.abs(yvel) > config.getVelocityThreshold() && !isSideSwiping){
settleTop = -screenHeight;
}else if(top < -topThreshold){
settleTop = -screenHeight;
}
}else{
if(top > topThreshold){
settleTop = screenHeight;
}else if(top < -topThreshold){
settleTop = -screenHeight;
}
}
dragHelper.settleCapturedViewAt(releasedChild.getLeft(), settleTop);
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)Math.abs(top) / (float) screenHeight);
if(listener != null) listener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(listener != null) listener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(decorView.getTop() == 0){
// State Open
if(listener != null) listener.onOpened();
}else{
// State Closed
if(listener != null) listener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break;
}
}
};
/**
* The drag helper callbacks for dragging the slidr attachment in both horizontal directions
*/
private final ViewDragHelper.Callback horizontalCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
boolean edgeCase = !config.isEdgeOnly() || dragHelper.isEdgeTouched(edgePosition, pointerId);
return child.getId() == decorView.getId() && edgeCase;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return clamp(left, -screenWidth, screenWidth);
}
@Override
public int getViewHorizontalDragRange(View child) {
return screenWidth;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int left = releasedChild.getLeft();
int settleLeft = 0;
int leftThreshold = (int) (getWidth() * config.getDistanceThreshold());
boolean isVerticalSwiping = Math.abs(yvel) > config.getVelocityThreshold();
if(xvel > 0){
if(Math.abs(xvel) > config.getVelocityThreshold() && !isVerticalSwiping){
settleLeft = screenWidth;
}else if(left > leftThreshold){
settleLeft = screenWidth;
}
}else if(xvel < 0){
if(Math.abs(xvel) > config.getVelocityThreshold() && !isVerticalSwiping){
settleLeft = -screenWidth;
}else if(left < -leftThreshold){
settleLeft = -screenWidth;
}
}else{
if(left > leftThreshold){
settleLeft = screenWidth;
}else if(left < -leftThreshold){
settleLeft = -screenWidth;
}
}
dragHelper.settleCapturedViewAt(settleLeft, releasedChild.getTop());
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)Math.abs(left) / (float) screenWidth);
if(listener != null) listener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(listener != null) listener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(decorView.getLeft() == 0){
// State Open
if(listener != null) listener.onOpened();
}else{
// State Closed
if(listener != null) listener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break;
}
}
};
private void init(){
setWillNotDraw(false);
screenWidth = getResources().getDisplayMetrics().widthPixels;
final float density = getResources().getDisplayMetrics().density;
final float minVel = MIN_FLING_VELOCITY * density;
ViewDragHelper.Callback callback;
switch (config.getPosition()){
case LEFT:
callback = leftCallback;
edgePosition = ViewDragHelper.EDGE_LEFT;
break;
case RIGHT:
callback = rightCallback;
edgePosition = ViewDragHelper.EDGE_RIGHT;
break;
case TOP:
callback = topCallback;
edgePosition = ViewDragHelper.EDGE_TOP;
break;
case BOTTOM:
callback = bottomCallback;
edgePosition = ViewDragHelper.EDGE_BOTTOM;
break;
case VERTICAL:
callback = verticalCallback;
edgePosition = ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_BOTTOM;
break;
case HORIZONTAL:
callback = horizontalCallback;
edgePosition = ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_RIGHT;
break;
default:
callback = leftCallback;
edgePosition = ViewDragHelper.EDGE_LEFT;
}
dragHelper = ViewDragHelper.create(this, config.getSensitivity(), callback);
dragHelper.setMinVelocity(minVel);
dragHelper.setEdgeTrackingEnabled(edgePosition);
ViewGroupCompat.setMotionEventSplittingEnabled(this, false);
// Setup the dimmer view
scrimPaint = new Paint();
scrimPaint.setColor(config.getScrimColor());
scrimPaint.setAlpha(toAlpha(config.getScrimStartAlpha()));
scrimRenderer = new ScrimRenderer(this, decorView);
/*
* This is so we can get the height of the view and
* ignore the system navigation that would be included if we
* retrieved this value from the DisplayMetrics
*/
post(new Runnable() {
@Override
public void run() {
screenHeight = getHeight();
}
});
}
private void lock(){
dragHelper.abort();
isLocked = true;
}
private void unlock(){
dragHelper.abort();
isLocked = false;
}
private boolean canDragFromEdge(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (config.getPosition()) {
case LEFT:
return x < config.getEdgeSize(getWidth());
case RIGHT:
return x > getWidth() - config.getEdgeSize(getWidth());
case BOTTOM:
return y > getHeight() - config.getEdgeSize(getHeight());
case TOP:
return y < config.getEdgeSize(getHeight());
case HORIZONTAL:
return x < config.getEdgeSize(getWidth()) || x > getWidth() - config.getEdgeSize(getWidth());
case VERTICAL:
return y < config.getEdgeSize(getHeight()) || y > getHeight() - config.getEdgeSize(getHeight());
}
return false;
}
private void applyScrim(float percent){
float alpha = (percent * (config.getScrimStartAlpha() - config.getScrimEndAlpha())) + config.getScrimEndAlpha();
scrimPaint.setAlpha(toAlpha(alpha));
invalidate(scrimRenderer.getDirtyRect(config.getPosition()));
}
private static int clamp(int value, int min, int max){
return Math.max(min, Math.min(max, value));
}
private static int toAlpha(float percentage) {
return (int) (percentage * 255);
}
/**
* The panel sliding interface that gets called
* whenever the panel is closed or opened
*/
public interface OnPanelSlideListener{
void onStateChanged(int state);
void onClosed();
void onOpened();
void onSlideChange(float percent);
}
}
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="slidable_panel" type="id" />
<item name="slidable_content" type="id" />
</resources>
-1
View File
@@ -1 +0,0 @@
/build
-25
View File
@@ -1,25 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdk
buildToolsVersion rootProject.ext.buildTools
defaultConfig {
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
-17
View File
@@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ybq/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-1
View File
@@ -1 +0,0 @@
<manifest package="com.github.ybq.android.spinkit" />
@@ -1,121 +0,0 @@
package com.github.ybq.android.spinkit;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ProgressBar;
import com.github.ybq.android.spinkit.sprite.Sprite;
/**
* Created by ybq.
*/
public class SpinKitView extends ProgressBar {
private Style mStyle;
private int mColor;
private Sprite mSprite;
public SpinKitView(Context context) {
this(context, null);
}
public SpinKitView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.SpinKitViewStyle);
}
public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, R.style.SpinKitView);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpinKitView, defStyleAttr,
defStyleRes);
mStyle = Style.values()[a.getInt(R.styleable.SpinKitView_SpinKit_Style, 0)];
mColor = a.getColor(R.styleable.SpinKitView_SpinKit_Color, Color.WHITE);
a.recycle();
init();
setIndeterminate(true);
}
private void init() {
Sprite sprite = SpriteFactory.create(mStyle);
sprite.setColor(mColor);
setIndeterminateDrawable(sprite);
}
@Override
public void setIndeterminateDrawable(Drawable d) {
if (!(d instanceof Sprite)) {
throw new IllegalArgumentException("this d must be instanceof Sprite");
}
setIndeterminateDrawable((Sprite) d);
}
public void setIndeterminateDrawable(Sprite d) {
super.setIndeterminateDrawable(d);
mSprite = d;
if (mSprite.getColor() == 0) {
mSprite.setColor(mColor);
}
onSizeChanged(getWidth(), getHeight(), getWidth(), getHeight());
if (getVisibility() == VISIBLE) {
mSprite.start();
}
}
@Override
public Sprite getIndeterminateDrawable() {
return mSprite;
}
public void setColor(int color) {
this.mColor = color;
if (mSprite != null) {
mSprite.setColor(color);
}
invalidate();
}
@Override
public void unscheduleDrawable(Drawable who) {
super.unscheduleDrawable(who);
if (who instanceof Sprite) {
((Sprite) who).stop();
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
if (mSprite != null && getVisibility() == VISIBLE) {
mSprite.start();
}
}
}
@Override
public void onScreenStateChanged(int screenState) {
super.onScreenStateChanged(screenState);
if (screenState == View.SCREEN_STATE_OFF) {
if (mSprite != null) {
mSprite.stop();
}
}
}
}
@@ -1,78 +0,0 @@
package com.github.ybq.android.spinkit;
import com.github.ybq.android.spinkit.sprite.Sprite;
import com.github.ybq.android.spinkit.style.ChasingDots;
import com.github.ybq.android.spinkit.style.Circle;
import com.github.ybq.android.spinkit.style.CubeGrid;
import com.github.ybq.android.spinkit.style.DoubleBounce;
import com.github.ybq.android.spinkit.style.FadingCircle;
import com.github.ybq.android.spinkit.style.FoldingCube;
import com.github.ybq.android.spinkit.style.MultiplePulse;
import com.github.ybq.android.spinkit.style.MultiplePulseRing;
import com.github.ybq.android.spinkit.style.Pulse;
import com.github.ybq.android.spinkit.style.PulseRing;
import com.github.ybq.android.spinkit.style.RotatingCircle;
import com.github.ybq.android.spinkit.style.RotatingPlane;
import com.github.ybq.android.spinkit.style.ThreeBounce;
import com.github.ybq.android.spinkit.style.WanderingCubes;
import com.github.ybq.android.spinkit.style.Wave;
/**
* Created by ybq.
*/
public class SpriteFactory {
public static Sprite create(Style style) {
Sprite sprite = null;
switch (style) {
case ROTATING_PLANE:
sprite = new RotatingPlane();
break;
case DOUBLE_BOUNCE:
sprite = new DoubleBounce();
break;
case WAVE:
sprite = new Wave();
break;
case WANDERING_CUBES:
sprite = new WanderingCubes();
break;
case PULSE:
sprite = new Pulse();
break;
case CHASING_DOTS:
sprite = new ChasingDots();
break;
case THREE_BOUNCE:
sprite = new ThreeBounce();
break;
case CIRCLE:
sprite = new Circle();
break;
case CUBE_GRID:
sprite = new CubeGrid();
break;
case FADING_CIRCLE:
sprite = new FadingCircle();
break;
case FOLDING_CUBE:
sprite = new FoldingCube();
break;
case ROTATING_CIRCLE:
sprite = new RotatingCircle();
break;
case MULTIPLE_PULSE:
sprite = new MultiplePulse();
break;
case PULSE_RING:
sprite = new PulseRing();
break;
case MULTIPLE_PULSE_RING:
sprite = new MultiplePulseRing();
break;
default:
break;
}
return sprite;
}
}
@@ -1,30 +0,0 @@
package com.github.ybq.android.spinkit;
/**
* Created by ybq.
*/
public enum Style {
ROTATING_PLANE(0),
DOUBLE_BOUNCE(1),
WAVE(2),
WANDERING_CUBES(3),
PULSE(4),
CHASING_DOTS(5),
THREE_BOUNCE(6),
CIRCLE(7),
CUBE_GRID(8),
FADING_CIRCLE(9),
FOLDING_CUBE(10),
ROTATING_CIRCLE(11),
MULTIPLE_PULSE(12),
PULSE_RING(13),
MULTIPLE_PULSE_RING(14);
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private int value;
Style(int value) {
this.value = value;
}
}
@@ -1,53 +0,0 @@
package com.github.ybq.android.spinkit.animation;
import android.animation.Animator;
import android.animation.ValueAnimator;
import com.github.ybq.android.spinkit.sprite.Sprite;
/**
* Created by ybq.
*/
public class AnimationUtils {
public static void start(Animator animator) {
if (animator != null && !animator.isStarted()) {
animator.start();
}
}
public static void stop(Animator animator) {
if (animator != null && !animator.isRunning()) {
animator.end();
}
}
public static void start(Sprite... sprites) {
for (Sprite sprite : sprites) {
sprite.start();
}
}
public static void stop(Sprite... sprites) {
for (Sprite sprite : sprites) {
sprite.stop();
}
}
public static boolean isRunning(Sprite... sprites) {
for (Sprite sprite : sprites) {
if (sprite.isRunning()) {
return true;
}
}
return false;
}
public static boolean isRunning(ValueAnimator animator) {
return animator != null && animator.isRunning();
}
public static boolean isStarted(ValueAnimator animator) {
return animator != null && animator.isStarted();
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.ybq.android.spinkit.animation;
import android.util.Property;
/**
* An implementation of {@link android.util.Property} to be used specifically with fields of type
* <code>float</code>. This type-specific subclass enables performance benefit by allowing
* calls to a {@link #set(Object, Float) set()} function that takes the primitive
* <code>float</code> type and avoids autoboxing and other overhead associated with the
* <code>Float</code> class.
*
* @param <T> The class on which the Property is declared.
*/
public abstract class FloatProperty<T> extends Property<T, Float> {
public FloatProperty(String name) {
super(Float.class, name);
}
/**
* A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
* with fields of type <code>float</code>.
*/
public abstract void setValue(T object, float value);
@Override
final public void set(T object, Float value) {
setValue(object, value);
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.ybq.android.spinkit.animation;
import android.util.Property;
/**
* An implementation of {@link android.util.Property} to be used specifically with fields of type
* <code>int</code>. This type-specific subclass enables performance benefit by allowing
* calls to a {@link #set(Object, Integer) set()} function that takes the primitive
* <code>int</code> type and avoids autoboxing and other overhead associated with the
* <code>Integer</code> class.
*
* @param <T> The class on which the Property is declared.
*/
public abstract class IntProperty<T> extends Property<T, Integer> {
public IntProperty(String name) {
super(Integer.class, name);
}
/**
* A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
* with fields of type <code>int</code>.
*/
public abstract void setValue(T object, int value);
@Override
final public void set(T object, Integer value) {
setValue(object, value);
}
}
@@ -1,214 +0,0 @@
package com.github.ybq.android.spinkit.animation;
import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.util.Log;
import android.util.Property;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import com.github.ybq.android.spinkit.animation.interpolator.KeyFrameInterpolator;
import com.github.ybq.android.spinkit.sprite.Sprite;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Created by ybq.
*/
public class SpriteAnimatorBuilder {
private static final String TAG = "SpriteAnimatorBuilder";
private Sprite sprite;
private Interpolator interpolator;
private int repeatCount = Animation.INFINITE;
private long duration = 2000;
private int startFrame = 0;
private Map<String, FrameData> fds = new HashMap<>();
class FrameData<T> {
public FrameData(float[] fractions, Property property, T[] values) {
this.fractions = fractions;
this.property = property;
this.values = values;
}
float[] fractions;
Property property;
T[] values;
}
class IntFrameData extends FrameData<Integer> {
public IntFrameData(float[] fractions, Property property, Integer[] values) {
super(fractions, property, values);
}
}
class FloatFrameData extends FrameData<Float> {
public FloatFrameData(float[] fractions, Property property, Float[] values) {
super(fractions, property, values);
}
}
public SpriteAnimatorBuilder(Sprite sprite) {
this.sprite = sprite;
}
public SpriteAnimatorBuilder scale(float fractions[], Float... scale) {
holder(fractions, Sprite.SCALE, scale);
return this;
}
public SpriteAnimatorBuilder alpha(float fractions[], Integer... alpha) {
holder(fractions, Sprite.ALPHA, alpha);
return this;
}
@SuppressWarnings("unused")
public SpriteAnimatorBuilder scaleX(float fractions[], Float... scaleX) {
holder(fractions, Sprite.SCALE, scaleX);
return this;
}
public SpriteAnimatorBuilder scaleY(float fractions[], Float... scaleY) {
holder(fractions, Sprite.SCALE_Y, scaleY);
return this;
}
public SpriteAnimatorBuilder rotateX(float fractions[], Integer... rotateX) {
holder(fractions, Sprite.ROTATE_X, rotateX);
return this;
}
public SpriteAnimatorBuilder rotateY(float fractions[], Integer... rotateY) {
holder(fractions, Sprite.ROTATE_Y, rotateY);
return this;
}
@SuppressWarnings("unused")
public SpriteAnimatorBuilder translateX(float fractions[], Integer... translateX) {
holder(fractions, Sprite.TRANSLATE_X, translateX);
return this;
}
@SuppressWarnings("unused")
public SpriteAnimatorBuilder translateY(float fractions[], Integer... translateY) {
holder(fractions, Sprite.TRANSLATE_Y, translateY);
return this;
}
public SpriteAnimatorBuilder rotate(float fractions[], Integer... rotate) {
holder(fractions, Sprite.ROTATE, rotate);
return this;
}
public SpriteAnimatorBuilder translateXPercentage(float fractions[], Float... translateXPercentage) {
holder(fractions, Sprite.TRANSLATE_X_PERCENTAGE, translateXPercentage);
return this;
}
public SpriteAnimatorBuilder translateYPercentage(float[] fractions, Float... translateYPercentage) {
holder(fractions, Sprite.TRANSLATE_Y_PERCENTAGE, translateYPercentage);
return this;
}
private void holder(float[] fractions, Property property, Float[] values) {
ensurePair(fractions.length, values.length);
fds.put(property.getName(), new FloatFrameData(fractions, property, values));
}
private void holder(float[] fractions, Property property, Integer[] values) {
ensurePair(fractions.length, values.length);
fds.put(property.getName(), new IntFrameData(fractions, property, values));
}
private void ensurePair(int fractionsLength, int valuesLength) {
if (fractionsLength != valuesLength) {
throw new IllegalStateException(String.format(
Locale.getDefault(),
"The fractions.length must equal values.length, " +
"fraction.length[%d], values.length[%d]",
fractionsLength,
valuesLength));
}
}
public SpriteAnimatorBuilder interpolator(Interpolator interpolator) {
this.interpolator = interpolator;
return this;
}
public SpriteAnimatorBuilder easeInOut(float... fractions) {
interpolator(KeyFrameInterpolator.easeInOut(
fractions
));
return this;
}
public SpriteAnimatorBuilder duration(long duration) {
this.duration = duration;
return this;
}
@SuppressWarnings("unused")
public SpriteAnimatorBuilder repeatCount(int repeatCount) {
this.repeatCount = repeatCount;
return this;
}
public SpriteAnimatorBuilder startFrame(int startFrame) {
if (startFrame < 0) {
Log.w(TAG, "startFrame should always be non-negative");
startFrame = 0;
}
this.startFrame = startFrame;
return this;
}
public ObjectAnimator build() {
PropertyValuesHolder[] holders = new PropertyValuesHolder[fds.size()];
int i = 0;
for (Map.Entry<String, FrameData> fd : fds.entrySet()) {
FrameData data = fd.getValue();
Keyframe[] keyframes = new Keyframe[data.fractions.length];
float[] fractions = data.fractions;
float startF = fractions[startFrame];
for (int j = startFrame; j < (startFrame + data.values.length); j++) {
int key = j - startFrame;
int vk = j % data.values.length;
float fraction = fractions[vk] - startF;
if (fraction < 0) {
fraction = fractions[fractions.length - 1] + fraction;
}
if (data instanceof IntFrameData) {
keyframes[key] = Keyframe.ofInt(fraction, (Integer) data.values[vk]);
} else if (data instanceof FloatFrameData) {
keyframes[key] = Keyframe.ofFloat(fraction, (Float) data.values[vk]);
} else {
keyframes[key] = Keyframe.ofObject(fraction, data.values[vk]);
}
}
holders[i] = PropertyValuesHolder.ofKeyframe(data.property, keyframes);
i++;
}
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(sprite,
holders);
animator.setDuration(duration);
animator.setRepeatCount(repeatCount);
animator.setInterpolator(interpolator);
return animator;
}
}
@@ -1,12 +0,0 @@
package com.github.ybq.android.spinkit.animation.interpolator;
import android.view.animation.Interpolator;
/**
* Created by ybq.
*/
public class Ease {
public static Interpolator inOut() {
return PathInterpolatorCompat.create(0.42f, 0f, 0.58f, 1f);
}
}
@@ -1,54 +0,0 @@
package com.github.ybq.android.spinkit.animation.interpolator;
import android.animation.TimeInterpolator;
import android.view.animation.Interpolator;
/**
* Created by ybq.
*/
public class KeyFrameInterpolator implements Interpolator {
private TimeInterpolator interpolator;
private float[] fractions;
public static KeyFrameInterpolator easeInOut(float... fractions) {
KeyFrameInterpolator interpolator = new KeyFrameInterpolator(Ease.inOut());
interpolator.setFractions(fractions);
return interpolator;
}
public static KeyFrameInterpolator pathInterpolator(float controlX1, float controlY1,
float controlX2, float controlY2,
float... fractions) {
KeyFrameInterpolator interpolator = new KeyFrameInterpolator(PathInterpolatorCompat.create(controlX1, controlY1, controlX2, controlY2));
interpolator.setFractions(fractions);
return interpolator;
}
public KeyFrameInterpolator(TimeInterpolator interpolator, float... fractions) {
this.interpolator = interpolator;
this.fractions = fractions;
}
public void setFractions(float... fractions) {
this.fractions = fractions;
}
@Override
public float getInterpolation(float input) {
if (fractions.length > 1) {
for (int i = 0; i < fractions.length - 1; i++) {
float start = fractions[i];
float end = fractions[i + 1];
float duration = end - start;
if (input >= start && input <= end) {
input = (input - start) / duration;
return start + (interpolator.getInterpolation(input)
* duration);
}
}
}
return interpolator.getInterpolation(input);
}
}
@@ -1,87 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.ybq.android.spinkit.animation.interpolator;
import android.graphics.Path;
import android.os.Build;
import android.view.animation.Interpolator;
/**
* Helper for creating path-based {@link Interpolator} instances. On API 21 or newer, the
* platform implementation will be used and on older platforms a compatible alternative
* implementation will be used.
*/
public class PathInterpolatorCompat {
private PathInterpolatorCompat() {
// prevent instantiation
}
/**
* Create an {@link Interpolator} for an arbitrary {@link Path}. The {@link Path}
* must begin at {@code (0, 0)} and end at {@code (1, 1)}. The x-coordinate along the
* {@link Path} is the input value and the output is the y coordinate of the line at that
* point. This means that the Path must conform to a function {@code y = f(x)}.
* <p>
* The {@link Path} must not have gaps in the x direction and must not
* loop back on itself such that there can be two points sharing the same x coordinate.
*
* @param path the {@link Path} to use to make the line representing the {@link Interpolator}
* @return the {@link Interpolator} representing the {@link Path}
*/
@SuppressWarnings("unused")
public static Interpolator create(Path path) {
if (Build.VERSION.SDK_INT >= 21) {
return PathInterpolatorCompatApi21.create(path);
}
return PathInterpolatorCompatBase.create(path);
}
/**
* Create an {@link Interpolator} for a quadratic Bezier curve. The end points
* {@code (0, 0)} and {@code (1, 1)} are assumed.
*
* @param controlX the x coordinate of the quadratic Bezier control point
* @param controlY the y coordinate of the quadratic Bezier control point
* @return the {@link Interpolator} representing the quadratic Bezier curve
*/
@SuppressWarnings("unused")
public static Interpolator create(float controlX, float controlY) {
if (Build.VERSION.SDK_INT >= 21) {
return PathInterpolatorCompatApi21.create(controlX, controlY);
}
return PathInterpolatorCompatBase.create(controlX, controlY);
}
/**
* Create an {@link Interpolator} for a cubic Bezier curve. The end points
* {@code (0, 0)} and {@code (1, 1)} are assumed.
*
* @param controlX1 the x coordinate of the first control point of the cubic Bezier
* @param controlY1 the y coordinate of the first control point of the cubic Bezier
* @param controlX2 the x coordinate of the second control point of the cubic Bezier
* @param controlY2 the y coordinate of the second control point of the cubic Bezier
* @return the {@link Interpolator} representing the cubic Bezier curve
*/
public static Interpolator create(float controlX1, float controlY1,
float controlX2, float controlY2) {
if (Build.VERSION.SDK_INT >= 21) {
return PathInterpolatorCompatApi21.create(controlX1, controlY1, controlX2, controlY2);
}
return PathInterpolatorCompatBase.create(controlX1, controlY1, controlX2, controlY2);
}
}
@@ -1,49 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.ybq.android.spinkit.animation.interpolator;
import android.annotation.TargetApi;
import android.graphics.Path;
import android.os.Build;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
/**
* API 21+ implementation for path interpolator compatibility.
*/
class PathInterpolatorCompatApi21 {
private PathInterpolatorCompatApi21() {
// prevent instantiation
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Interpolator create(Path path) {
return new PathInterpolator(path);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Interpolator create(float controlX, float controlY) {
return new PathInterpolator(controlX, controlY);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Interpolator create(float controlX1, float controlY1,
float controlX2, float controlY2) {
return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);
}
}

Some files were not shown because too many files have changed in this diff Show More