diff options
author | Thomas <tschneider.ac@gmail.com> | 2023-01-16 16:33:20 +0100 |
---|---|---|
committer | Thomas <tschneider.ac@gmail.com> | 2023-01-16 16:33:20 +0100 |
commit | d5c51e6dcaadf1a91bdb5fbc693e859d3124ad5a (patch) | |
tree | 29100df2297289185d6b50bf404a06e3a320d79d | |
parent | 25ad71080e261de9b418341c8e3c0f21fff6b405 (diff) |
Add support for maths.
8 files changed, 112 insertions, 37 deletions
diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index f6c35ba65..6ea6179ac 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -327,7 +327,8 @@ public class Helper { public static final Pattern groupPattern = Pattern.compile("(![\\w_]+)"); public static final Pattern mentionPattern = Pattern.compile("(@[\\w_.-]?[\\w]+)"); public static final Pattern mentionLongPattern = Pattern.compile("(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)"); - public static final Pattern mathsPattern = Pattern.compile("\\\\\\(|\\\\\\{|\\\\\\["); + public static final Pattern mathsPattern = Pattern.compile("\\\\\\(|\\\\\\["); + public static final Pattern mathsComposePattern = Pattern.compile("\\\\\\(.*\\\\\\)|\\\\\\[.*\\\\\\]"); public static final Pattern twitterPattern = Pattern.compile("((@[\\w]+)@twitter\\.com)"); public static final Pattern youtubePattern = Pattern.compile("(www\\.|m\\.)?(youtube\\.com|youtu\\.be|youtube-nocookie\\.com)/(((?!([\"'<])).)*)"); public static final Pattern nitterPattern = Pattern.compile("(mobile\\.|www\\.)?twitter.com([\\w-/]+)"); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 7933713e8..5c580ae62 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; @@ -531,7 +532,9 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder if (promptDraftListener != null) { promptDraftListener.promptDraft(); } - statusList.get(holder.getLayoutPosition()).cursorPosition = holder.binding.content.getSelectionStart(); + if (holder.binding.content.getSelectionStart() > 0) { + statusList.get(holder.getLayoutPosition()).cursorPosition = holder.binding.content.getSelectionStart(); + } //Copy/past int max_car = MastodonHelper.getInstanceMaxChars(context); if (currentLength > max_car) { @@ -694,6 +697,24 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder updateCharacterCount(holder); return; } + Matcher mathsPatterns = Helper.mathsComposePattern.matcher((s.toString())); + if (mathsPatterns.find()) { + if (holder.binding.laTexViewContainer.getVisibility() != View.VISIBLE) { + holder.binding.laTexViewContainer.setVisibility(View.VISIBLE); + + switch (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) { + case Configuration.UI_MODE_NIGHT_YES: + holder.binding.laTexView.setTextColor("white"); + break; + case Configuration.UI_MODE_NIGHT_NO: + holder.binding.laTexView.setTextColor("black"); + break; + } + } + holder.binding.laTexView.setInputText(s.toString()); + } else { + holder.binding.laTexViewContainer.setVisibility(View.GONE); + } String patternh = "^(.|\\s)*(:fedilab_hugs:)"; final Pattern hPattern = Pattern.compile(patternh); @@ -1272,7 +1293,34 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder ComposeViewHolder holder = (ComposeViewHolder) viewHolder; boolean extraFeatures = sharedpreferences.getBoolean(context.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false); + boolean mathsComposer = sharedpreferences.getBoolean(context.getString(R.string.SET_MATHS_COMPOSER), true); + if (mathsComposer) { + holder.binding.buttonMathsComposer.setVisibility(View.VISIBLE); + holder.binding.buttonMathsComposer.setOnClickListener(v -> { + int cursorPosition = holder.binding.content.getSelectionStart(); + AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle()); + Resources res = context.getResources(); + String[] formatArr = res.getStringArray(R.array.SET_MATHS_FORMAT); + builder.setItems(formatArr, (dialogInterface, i) -> { + if (statusDraft.text == null) { + statusDraft.text = ""; + } + if (i == 0) { + statusDraft.text = new StringBuilder(statusDraft.text).insert(cursorPosition, "\\( \\)").toString(); + } else { + statusDraft.text = new StringBuilder(statusDraft.text).insert(cursorPosition, "\\[ \\]").toString(); + } + statusDraft.cursorPosition = cursorPosition + 3; + notifyItemChanged(position); + dialogInterface.dismiss(); + }); + builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + builder.create().show(); + }); + } else { + holder.binding.buttonMathsComposer.setVisibility(View.GONE); + } holder.binding.buttonEmojiOne.setVisibility(View.VISIBLE); if (extraFeatures) { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index af9c1ddfc..eeff36c46 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -674,9 +674,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> mathJaxConfig.setTextColor("white"); break; case Configuration.UI_MODE_NIGHT_NO: - mathJaxConfig.setTextColor("dark"); + mathJaxConfig.setTextColor("black"); break; } + mathJaxConfig.setAutomaticLinebreaks(true); status.mathsShown = true; MathJaxView mathview = new MathJaxView(context, mathJaxConfig); holder.binding.statusContentMaths.addView(mathview); diff --git a/app/src/main/res/layout/drawer_status_compose.xml b/app/src/main/res/layout/drawer_status_compose.xml index 81e2173e1..b191643b9 100644 --- a/app/src/main/res/layout/drawer_status_compose.xml +++ b/app/src/main/res/layout/drawer_status_compose.xml @@ -32,6 +32,27 @@ android:clipToPadding="false" android:orientation="vertical"> + <androidx.core.widget.NestedScrollView + android:id="@+id/laTexView_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone" + app:layout_constraintBottom_toTopOf="@+id/button_emoji" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <de.timfreiheit.mathjax.android.MathJaxView + android:id="@+id/laTexView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + app:automaticLinebreaks="true" + app:input="TeX" + app:output="SVG" /> + </androidx.core.widget.NestedScrollView> + + <com.google.android.material.textfield.MaterialAutoCompleteTextView android:id="@+id/content_spoiler" android:layout_width="0dp" @@ -44,7 +65,7 @@ android:visibility="gone" app:layout_constraintEnd_toStartOf="@id/button_emoji" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" + app:layout_constraintTop_toBottomOf="@+id/laTexView_container" tools:visibility="visible" /> <com.google.android.material.button.MaterialButton @@ -55,7 +76,7 @@ android:contentDescription="@string/add_status" app:icon="@drawable/ic_compose_thread_add_status" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/laTexView_container" /> <app.fedilab.android.helper.FedilabAutoCompleteTextView android:id="@+id/content" @@ -104,6 +125,17 @@ tools:visibility="visible" /> <com.google.android.material.button.MaterialButton + android:id="@+id/button_maths_composer" + style="@style/Fedilab.SmallIconButton" + android:layout_marginEnd="6dp" + android:contentDescription="@string/maths_format" + android:visibility="gone" + app:icon="@drawable/ic_baseline_functions_24" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/button_text_format" + tools:visibility="visible" /> + + <com.google.android.material.button.MaterialButton android:id="@+id/button_local_only" style="@style/Fedilab.SmallIconButton" android:layout_marginEnd="6dp" @@ -111,7 +143,7 @@ android:visibility="gone" app:icon="@drawable/ic_baseline_remove_red_eye_24" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/button_text_format" + app:layout_constraintTop_toBottomOf="@id/button_maths_composer" tools:visibility="visible" /> <com.google.android.material.checkbox.MaterialCheckBox diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1b4a5bf2a..410a27582 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -763,6 +763,12 @@ <item>Mastalab</item> </string-array> + + <string-array name="SET_MATHS_FORMAT"> + <item>Inline\nNotation that sits inline with other text\n</item> + <item>Display-mode\nNotation that sits on its own line\n</item> + </string-array> + <string-array name="SET_POST_FORMAT" translatable="false"> <item>text/plain</item> <item>text/html</item> @@ -1483,6 +1489,7 @@ <string name="SET_UNLISTED_REPLIES" translatable="false">SET_UNLISTED_REPLIES</string> <string name="SET_SELECTED_LANGUAGE" translatable="false">SET_SELECTED_LANGUAGE</string> <string name="SET_WATERMARK_TEXT" translatable="false">SET_WATERMARK_TEXT</string> + <string name="SET_MATHS_COMPOSER" translatable="false">SET_MATHS_COMPOSER</string> <string name="SET_PROXY_PASSWORD" translatable="false">SET_PROXY_PASSWORD</string> <string name="SET_PROXY_LOGIN" translatable="false">SET_PROXY_LOGIN</string> <string name="SET_ACCOUNTS_PER_CALL" translatable="false">SET_ACCOUNTS_PER_CALL</string> @@ -2214,4 +2221,6 @@ <string name="set_disable_release_notes">Disable release notes</string> <string name="set_disable_release_notes_indication">When a new version is published, you will not be alerted inside the app.</string> <string name="formula">Formula</string> + <string name="set_maths_support">Write formula</string> + <string name="maths_format">Maths format</string> </resources>
\ No newline at end of file diff --git a/app/src/main/res/xml/pref_compose.xml b/app/src/main/res/xml/pref_compose.xml index 4f263dd5f..250aa8921 100644 --- a/app/src/main/res/xml/pref_compose.xml +++ b/app/src/main/res/xml/pref_compose.xml @@ -60,6 +60,12 @@ app:key="@string/SET_WATERMARK_TEXT" app:useSimpleSummaryProvider="true" /> + <SwitchPreferenceCompat + app:defaultValue="true" + app:iconSpaceReserved="false" + app:key="@string/SET_MATHS_COMPOSER" + app:singleLineTitle="false" + app:title="@string/set_maths_support" /> <SwitchPreferenceCompat app:defaultValue="false" diff --git a/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxConfig.java b/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxConfig.java index e28ef8e1c..3dd1e70af 100644 --- a/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxConfig.java +++ b/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxConfig.java @@ -28,6 +28,7 @@ public class MathJaxConfig { } } + public MathJaxConfig(TypedArray attrs) { this(); int inputIndex = attrs.getInteger(R.styleable.MathJaxView_input, -1); diff --git a/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxView.java b/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxView.java index 401f2d661..a918cfa1f 100644 --- a/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxView.java +++ b/mathjaxandroid/src/main/java/de/timfreiheit/mathjax/android/MathJaxView.java @@ -9,17 +9,13 @@ import android.os.Handler; import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; -import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.FrameLayout; -import java.util.concurrent.atomic.AtomicReference; - /** * Containerview for an WebView which renders LaTex using MathJax @@ -88,20 +84,26 @@ public class MathJaxView extends FrameLayout { this.onMathJaxRenderListener = onMathJaxRenderListener; } + public void setTextColor(String color) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + mWebView.evaluateJavascript("document.body.style.color=\"" + color + "\";", null); + } + } + @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) private void init(Context context, AttributeSet attrSet, MathJaxConfig config) { mWebView = new WebView(context); int gravity = Gravity.START; boolean verticalScrollbarsEnabled = false; - boolean horizontalScrollbarsEnabled = true; + boolean horizontalScrollbarsEnabled = false; String textColor = config != null ? config.getTextColor() : null; if (attrSet != null) { TypedArray attrs = context.obtainStyledAttributes(attrSet, R.styleable.MathJaxView); gravity = attrs.getInteger(R.styleable.MathJaxView_android_gravity, Gravity.START); verticalScrollbarsEnabled = attrs.getBoolean(R.styleable.MathJaxView_verticalScrollbarsEnabled, false); - horizontalScrollbarsEnabled = attrs.getBoolean(R.styleable.MathJaxView_horizontalScrollbarsEnabled, true); + horizontalScrollbarsEnabled = attrs.getBoolean(R.styleable.MathJaxView_horizontalScrollbarsEnabled, false); textColor = attrs.getString(R.styleable.MathJaxView_textColor); config = new MathJaxConfig(attrs); attrs.recycle(); @@ -153,31 +155,6 @@ public class MathJaxView extends FrameLayout { mWebView.setHorizontalScrollBarEnabled(horizontalScrollbarsEnabled); mWebView.setBackgroundColor(0); mWebView.getSettings().setLoadWithOverviewMode(true); - float touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - final boolean[] scrollFlag = {true}; - AtomicReference<Float> downX = new AtomicReference<>((float) 0); - AtomicReference<Float> downY = new AtomicReference<>((float) 0); - mWebView.setOnTouchListener((View v, MotionEvent event) -> { - if (!scrollFlag[0] && event.getY() < getHeight() / 2) { - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - downX.set(event.getX()); - downY.set(event.getY()); - break; - case MotionEvent.ACTION_MOVE: - if (Math.abs(event.getY() - downY.get()) < touchSlop && Math.abs(event.getX() - downX.get()) > touchSlop) { - getParent().requestDisallowInterceptTouchEvent(true); - scrollFlag[0] = true; - } - break; - } - } - if (event.getAction() == MotionEvent.ACTION_UP) - scrollFlag[0] = false; - - return false; - }); } /** |