Merge pull request #221 from KirkBushman/master
added PrecomputedFutureTextSetterCompat
This commit is contained in:
		
						commit
						b48b0889da
					
				| @ -66,6 +66,7 @@ ext { | |||||||
|             'x-annotations'           : 'androidx.annotation:annotation:1.1.0', |             'x-annotations'           : 'androidx.annotation:annotation:1.1.0', | ||||||
|             'x-recycler-view'         : 'androidx.recyclerview:recyclerview:1.0.0', |             'x-recycler-view'         : 'androidx.recyclerview:recyclerview:1.0.0', | ||||||
|             'x-core'                  : 'androidx.core:core:1.0.2', |             'x-core'                  : 'androidx.core:core:1.0.2', | ||||||
|  |             'x-appcompat'             : 'androidx.appcompat:appcompat:1.1.0', | ||||||
|             'commonmark'              : "com.atlassian.commonmark:commonmark:$commonMarkVersion", |             'commonmark'              : "com.atlassian.commonmark:commonmark:$commonMarkVersion", | ||||||
|             'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion", |             'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion", | ||||||
|             'commonmark-table'        : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", |             'commonmark-table'        : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion", | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ dependencies { | |||||||
|         // @since 4.1.0 to allow PrecomputedTextSetterCompat |         // @since 4.1.0 to allow PrecomputedTextSetterCompat | ||||||
|         // note that this dependency must be added on a client side explicitly |         // note that this dependency must be added on a client side explicitly | ||||||
|         compileOnly it['x-core'] |         compileOnly it['x-core'] | ||||||
|  |         compileOnly it['x-appcompat'] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     deps['test'].with { |     deps['test'].with { | ||||||
|  | |||||||
| @ -0,0 +1,62 @@ | |||||||
|  | package io.noties.markwon; | ||||||
|  | 
 | ||||||
|  | import android.text.Spanned; | ||||||
|  | import android.util.Log; | ||||||
|  | import android.widget.TextView; | ||||||
|  | 
 | ||||||
|  | import androidx.annotation.NonNull; | ||||||
|  | import androidx.annotation.Nullable; | ||||||
|  | import androidx.appcompat.widget.AppCompatTextView; | ||||||
|  | import androidx.core.text.PrecomputedTextCompat; | ||||||
|  | 
 | ||||||
|  | import java.util.concurrent.Executor; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Please note this class requires `androidx.core:core` artifact being explicitly added to your dependencies. | ||||||
|  |  * This is intended to be used in a RecyclerView. | ||||||
|  |  * | ||||||
|  |  * @see io.noties.markwon.Markwon.TextSetter | ||||||
|  |  */ | ||||||
|  | public class PrecomputedFutureTextSetterCompat implements Markwon.TextSetter { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @param executor for background execution of text pre-computation, | ||||||
|  |      *                 if not provided the standard, single threaded one will be used. | ||||||
|  |      */ | ||||||
|  |     @NonNull | ||||||
|  |     public static PrecomputedFutureTextSetterCompat create(@Nullable Executor executor) { | ||||||
|  |         return new PrecomputedFutureTextSetterCompat(executor); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NonNull | ||||||
|  |     public static PrecomputedFutureTextSetterCompat create() { | ||||||
|  |         return new PrecomputedFutureTextSetterCompat(null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     private final Executor executor; | ||||||
|  | 
 | ||||||
|  |     @SuppressWarnings("WeakerAccess") | ||||||
|  |     PrecomputedFutureTextSetterCompat(@Nullable Executor executor) { | ||||||
|  |         this.executor = executor; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setText( | ||||||
|  |             @NonNull TextView textView, | ||||||
|  |             @NonNull Spanned markdown, | ||||||
|  |             @NonNull TextView.BufferType bufferType, | ||||||
|  |             @NonNull Runnable onComplete) { | ||||||
|  | 
 | ||||||
|  |         if (textView instanceof AppCompatTextView) { | ||||||
|  |             ((AppCompatTextView) textView).setTextFuture(PrecomputedTextCompat.getTextFuture( | ||||||
|  |                     markdown, ((AppCompatTextView) textView).getTextMetricsParamsCompat(), executor | ||||||
|  |             )); | ||||||
|  | 
 | ||||||
|  |             onComplete.run(); | ||||||
|  |         } else { | ||||||
|  | 
 | ||||||
|  |             throw new IllegalStateException("TextView provided is not a child of AppCompatTextView, cannot call setTextFuture()."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -54,6 +54,7 @@ dependencies { | |||||||
|     deps.with { |     deps.with { | ||||||
|         implementation it['x-recycler-view'] |         implementation it['x-recycler-view'] | ||||||
|         implementation it['x-core'] // for precomputedTextCompat |         implementation it['x-core'] // for precomputedTextCompat | ||||||
|  |         implementation it['x-appcompat'] // for setTextFuture | ||||||
|         implementation it['okhttp'] |         implementation it['okhttp'] | ||||||
|         implementation it['prism4j'] |         implementation it['prism4j'] | ||||||
|         implementation it['debug'] |         implementation it['debug'] | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ | |||||||
|         <activity android:name=".simpleext.SimpleExtActivity" /> |         <activity android:name=".simpleext.SimpleExtActivity" /> | ||||||
|         <activity android:name=".customextension2.CustomExtensionActivity2" /> |         <activity android:name=".customextension2.CustomExtensionActivity2" /> | ||||||
|         <activity android:name=".precomputed.PrecomputedActivity" /> |         <activity android:name=".precomputed.PrecomputedActivity" /> | ||||||
|  |         <activity android:name=".precomputed.PrecomputedFutureActivity" /> | ||||||
| 
 | 
 | ||||||
|         <activity |         <activity | ||||||
|             android:name=".editor.EditorActivity" |             android:name=".editor.EditorActivity" | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ import io.noties.markwon.sample.inlineparser.InlineParserActivity; | |||||||
| import io.noties.markwon.sample.latex.LatexActivity; | import io.noties.markwon.sample.latex.LatexActivity; | ||||||
| import io.noties.markwon.sample.notification.NotificationActivity; | import io.noties.markwon.sample.notification.NotificationActivity; | ||||||
| import io.noties.markwon.sample.precomputed.PrecomputedActivity; | import io.noties.markwon.sample.precomputed.PrecomputedActivity; | ||||||
|  | import io.noties.markwon.sample.precomputed.PrecomputedFutureActivity; | ||||||
| import io.noties.markwon.sample.recycler.RecyclerActivity; | import io.noties.markwon.sample.recycler.RecyclerActivity; | ||||||
| import io.noties.markwon.sample.simpleext.SimpleExtActivity; | import io.noties.markwon.sample.simpleext.SimpleExtActivity; | ||||||
| import io.noties.markwon.sample.table.TableActivity; | import io.noties.markwon.sample.table.TableActivity; | ||||||
| @ -124,6 +125,10 @@ public class MainActivity extends Activity { | |||||||
|                 activity = PrecomputedActivity.class; |                 activity = PrecomputedActivity.class; | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|  |             case PRECOMPUTED_FUTURE_TEXT: | ||||||
|  |                 activity = PrecomputedFutureActivity.class; | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|             case EDITOR: |             case EDITOR: | ||||||
|                 activity = EditorActivity.class; |                 activity = EditorActivity.class; | ||||||
|                 break; |                 break; | ||||||
|  | |||||||
| @ -23,6 +23,8 @@ public enum Sample { | |||||||
| 
 | 
 | ||||||
|     PRECOMPUTED_TEXT(R.string.sample_precomputed_text), |     PRECOMPUTED_TEXT(R.string.sample_precomputed_text), | ||||||
| 
 | 
 | ||||||
|  |     PRECOMPUTED_FUTURE_TEXT(R.string.sample_precomputed_future_text), | ||||||
|  | 
 | ||||||
|     EDITOR(R.string.sample_editor), |     EDITOR(R.string.sample_editor), | ||||||
| 
 | 
 | ||||||
|     INLINE_PARSER(R.string.sample_inline_parser), |     INLINE_PARSER(R.string.sample_inline_parser), | ||||||
|  | |||||||
| @ -0,0 +1,95 @@ | |||||||
|  | package io.noties.markwon.sample.precomputed; | ||||||
|  | 
 | ||||||
|  | import android.app.Activity; | ||||||
|  | import android.content.Context; | ||||||
|  | import android.os.Bundle; | ||||||
|  | 
 | ||||||
|  | import androidx.annotation.NonNull; | ||||||
|  | import androidx.annotation.Nullable; | ||||||
|  | import androidx.recyclerview.widget.LinearLayoutManager; | ||||||
|  | import androidx.recyclerview.widget.RecyclerView; | ||||||
|  | 
 | ||||||
|  | import java.io.BufferedReader; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.io.InputStreamReader; | ||||||
|  | 
 | ||||||
|  | import io.noties.markwon.Markwon; | ||||||
|  | import io.noties.markwon.PrecomputedFutureTextSetterCompat; | ||||||
|  | import io.noties.markwon.recycler.MarkwonAdapter; | ||||||
|  | import io.noties.markwon.sample.R; | ||||||
|  | 
 | ||||||
|  | public class PrecomputedFutureActivity extends Activity { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected void onCreate(@Nullable Bundle savedInstanceState) { | ||||||
|  |         super.onCreate(savedInstanceState); | ||||||
|  |         setContentView(R.layout.activity_recycler); | ||||||
|  | 
 | ||||||
|  |         final Markwon markwon = Markwon.builder(this) | ||||||
|  |                 .textSetter(PrecomputedFutureTextSetterCompat.create()) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         // create MarkwonAdapter and register two blocks that will be rendered differently | ||||||
|  |         final MarkwonAdapter adapter = MarkwonAdapter.builder(R.layout.adapter_appcompat_default_entry, R.id.text) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         final RecyclerView recyclerView = findViewById(R.id.recycler_view); | ||||||
|  |         recyclerView.setLayoutManager(new LinearLayoutManager(this)); | ||||||
|  |         recyclerView.setHasFixedSize(true); | ||||||
|  |         recyclerView.setAdapter(adapter); | ||||||
|  | 
 | ||||||
|  |         adapter.setMarkdown(markwon, loadReadMe(this)); | ||||||
|  | 
 | ||||||
|  |         // please note that we should notify updates (adapter doesn't do it implicitly) | ||||||
|  |         adapter.notifyDataSetChanged(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NonNull | ||||||
|  |     private static String loadReadMe(@NonNull Context context) { | ||||||
|  |         InputStream stream = null; | ||||||
|  |         try { | ||||||
|  |             stream = context.getAssets().open("README.md"); | ||||||
|  |         } catch (IOException e) { | ||||||
|  |             e.printStackTrace(); | ||||||
|  |         } | ||||||
|  |         return readStream(stream); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NonNull | ||||||
|  |     private static String readStream(@Nullable InputStream inputStream) { | ||||||
|  | 
 | ||||||
|  |         String out = null; | ||||||
|  | 
 | ||||||
|  |         if (inputStream != null) { | ||||||
|  |             BufferedReader reader = null; | ||||||
|  |             //noinspection TryFinallyCanBeTryWithResources | ||||||
|  |             try { | ||||||
|  |                 reader = new BufferedReader(new InputStreamReader(inputStream)); | ||||||
|  |                 final StringBuilder builder = new StringBuilder(); | ||||||
|  |                 String line; | ||||||
|  |                 while ((line = reader.readLine()) != null) { | ||||||
|  |                     builder.append(line) | ||||||
|  |                             .append('\n'); | ||||||
|  |                 } | ||||||
|  |                 out = builder.toString(); | ||||||
|  |             } catch (IOException e) { | ||||||
|  |                 e.printStackTrace(); | ||||||
|  |             } finally { | ||||||
|  |                 if (reader != null) { | ||||||
|  |                     try { | ||||||
|  |                         reader.close(); | ||||||
|  |                     } catch (IOException e) { | ||||||
|  |                         // no op | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (out == null) { | ||||||
|  |             throw new RuntimeException("Cannot read stream"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return out; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <androidx.appcompat.widget.AppCompatTextView | ||||||
|  |     xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     xmlns:tools="http://schemas.android.com/tools" | ||||||
|  |     android:id="@+id/text" | ||||||
|  |     android:layout_width="match_parent" | ||||||
|  |     android:layout_height="wrap_content" | ||||||
|  |     android:layout_marginLeft="16dip" | ||||||
|  |     android:layout_marginRight="16dip" | ||||||
|  |     android:lineSpacingExtra="2dip" | ||||||
|  |     android:paddingTop="8dip" | ||||||
|  |     android:paddingBottom="8dip" | ||||||
|  |     android:textAppearance="?android:attr/textAppearanceMedium" | ||||||
|  |     android:textColor="#000" | ||||||
|  |     android:textSize="16sp" | ||||||
|  |     tools:text="Hello" /> | ||||||
| @ -25,6 +25,8 @@ | |||||||
| 
 | 
 | ||||||
|     <string name="sample_precomputed_text"># \# PrecomputedText\n\nUsage of TextSetter and PrecomputedTextCompat</string> |     <string name="sample_precomputed_text"># \# PrecomputedText\n\nUsage of TextSetter and PrecomputedTextCompat</string> | ||||||
| 
 | 
 | ||||||
|  |     <string name="sample_precomputed_future_text"># \# PrecomputedFutureText\n\nUsage of TextSetter and PrecomputedFutureTextSetterCompat</string> | ||||||
|  | 
 | ||||||
|     <string name="sample_editor"># \# Editor\n\n`MarkwonEditor` sample usage to highlight user input in EditText</string> |     <string name="sample_editor"># \# Editor\n\n`MarkwonEditor` sample usage to highlight user input in EditText</string> | ||||||
| 
 | 
 | ||||||
|     <string name="sample_inline_parser"># \# Inline Parser\n\nUsage of custom inline parser</string> |     <string name="sample_inline_parser"># \# Inline Parser\n\nUsage of custom inline parser</string> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry
						Dimitry