├── app ├── .gitignore ├── src │ ├── main │ │ ├── assets │ │ │ ├── nodz.gif │ │ │ ├── hovercat.gif │ │ │ ├── top_pane-1.9.4.jpg │ │ │ ├── articles │ │ │ │ ├── SZ_250.jpg │ │ │ │ ├── lessonone.png │ │ │ │ ├── opto_LIGLUR.png │ │ │ │ ├── opto_opener.png │ │ │ │ ├── opto_sidebar.jpg │ │ │ │ ├── market-qr-code.png │ │ │ │ ├── channelrhodopsin-2.gif │ │ │ │ ├── kbogla_largecover.jpg │ │ │ │ ├── lessonone-180x300.png │ │ │ │ ├── opto_damagedretina.png │ │ │ │ ├── wt_javasparrow_free.jpg │ │ │ │ ├── rtl_test_2.html │ │ │ │ ├── gif_animation.html │ │ │ │ ├── science2a.html │ │ │ │ └── rtl_test.html │ │ │ ├── game-screen-1.9.4.jpg │ │ │ ├── right_pane-1.9.4.jpg │ │ │ ├── fonts │ │ │ │ └── GamjaFlower-Regular.ttf │ │ │ └── about.html │ │ ├── ic_real-web.png │ │ ├── ic_article-web.png │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── pinfish.jpg │ │ │ │ └── pinfish_small.jpg │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_logo.png │ │ │ │ ├── ic_real.png │ │ │ │ ├── ic_article.png │ │ │ │ ├── ic_columns.png │ │ │ │ └── ic_play_button.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_logo.png │ │ │ │ ├── ic_real.png │ │ │ │ ├── ic_article.png │ │ │ │ ├── ic_columns.png │ │ │ │ └── ic_play_button.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_logo.png │ │ │ │ ├── ic_real.png │ │ │ │ ├── ic_article.png │ │ │ │ ├── ic_columns.png │ │ │ │ └── ic_play_button.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_logo.png │ │ │ │ ├── ic_real.png │ │ │ │ ├── ic_article.png │ │ │ │ ├── ic_columns.png │ │ │ │ └── ic_play_button.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_logo.png │ │ │ │ ├── ic_real.png │ │ │ │ ├── ic_article.png │ │ │ │ ├── ic_columns.png │ │ │ │ ├── ic_hyphen.png │ │ │ │ ├── ic_justify.png │ │ │ │ ├── ic_image_wrap.png │ │ │ │ ├── ic_play_button.png │ │ │ │ ├── ic_select_text.png │ │ │ │ └── ic_battle_for_wesnoth.png │ │ │ ├── drawable-hdpi │ │ │ │ ├── ic_hyphen.png │ │ │ │ ├── ic_justify.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_image_wrap.png │ │ │ │ ├── ic_action_name.png │ │ │ │ ├── ic_select_text.png │ │ │ │ └── ic_battle_for_wesnoth.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── ic_hyphen.png │ │ │ │ ├── ic_justify.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_image_wrap.png │ │ │ │ ├── ic_action_name.png │ │ │ │ ├── ic_select_text.png │ │ │ │ └── ic_battle_for_wesnoth.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── ic_hyphen.png │ │ │ │ ├── ic_justify.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_action_name.png │ │ │ │ ├── ic_image_wrap.png │ │ │ │ ├── ic_select_text.png │ │ │ │ └── ic_battle_for_wesnoth.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── ic_hyphen.png │ │ │ │ ├── ic_justify.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_action_name.png │ │ │ │ ├── ic_image_wrap.png │ │ │ │ ├── ic_select_text.png │ │ │ │ └── ic_battle_for_wesnoth.png │ │ │ ├── xml │ │ │ │ └── activity_textview_ws_help.xml │ │ │ ├── values │ │ │ │ ├── styles.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── help.xml │ │ │ │ └── strings.xml │ │ │ ├── layout │ │ │ │ ├── acitivity_multi_column_text_view_ex.xml │ │ │ │ ├── activity_another_hyphen_text_view_ex.xml │ │ │ │ ├── activity_articles_flow.xml │ │ │ │ ├── activity_about.xml │ │ │ │ ├── activity_text_view_ws.xml │ │ │ │ ├── activity_hyphen_text_view_ex.xml │ │ │ │ ├── activity_multi_column_text_view_ex.xml │ │ │ │ ├── samples_list_item.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── activity_text_view_ex_scroll.xml │ │ │ │ ├── records_list_item.xml │ │ │ │ ├── activity_recycler_view.xml │ │ │ │ └── article_page_view.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── menu │ │ │ │ ├── menu_main.xml │ │ │ │ ├── menu_about.xml │ │ │ │ ├── menu_articles_flow.xml │ │ │ │ ├── menu_text_view_w.xml │ │ │ │ ├── menu_hyphen_text_view_ex.xml │ │ │ │ ├── menu_multi_column_text_view_ex.xml │ │ │ │ ├── menu_another_hyphen_text_view_ex.xml │ │ │ │ ├── text_options.xml │ │ │ │ └── menu_text_view_ex_scroll.xml │ │ │ └── layout-land │ │ │ │ └── activity_multi_column_text_view_ex.xml │ │ ├── java │ │ │ └── su │ │ │ │ └── whs │ │ │ │ └── watl │ │ │ │ └── samples │ │ │ │ ├── ArticleView.java │ │ │ │ ├── TaggedBitmapDrawable.java │ │ │ │ ├── TextPager.java │ │ │ │ ├── TextViewWSActivity.java │ │ │ │ ├── SampleActionModeCallback.java │ │ │ │ ├── GifDrawableCompat.java │ │ │ │ ├── MultiColumnTextViewExActivity.java │ │ │ │ ├── TextOptionsHandler.java │ │ │ │ ├── HyphenTextViewExActivity.java │ │ │ │ ├── RTLTestActivity.java │ │ │ │ ├── AssetGifDrawable.java │ │ │ │ ├── TextViewExScrollActivity.java │ │ │ │ ├── AnimationActivity.java │ │ │ │ ├── utils │ │ │ │ └── ArticleSerializer.java │ │ │ │ ├── ReaderViewPagerTransformer.java │ │ │ │ ├── AboutActivity.java │ │ │ │ ├── AnotherHyphenTextViewExActivity.java │ │ │ │ └── wATLApp.java │ │ └── AndroidManifest.xml │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── watl │ │ └── ApplicationTest.java ├── proguard-rules.pro └── build.gradle ├── htmlparser ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── htmlparser │ │ │ └── Html.java │ ├── test │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── htmlparser │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── htmlparser │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── mediaview ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── java │ │ │ └── su │ │ │ │ └── whs │ │ │ │ └── mediaview │ │ │ │ ├── IMediaView.java │ │ │ │ └── MediaContainer.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── mediaview │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── mediaview │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── syllabification ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── resources │ │ │ └── hyphenation-rules │ │ │ │ ├── fr.hyphen.dat │ │ │ │ └── pt.hyphen.dat │ │ ├── java │ │ │ └── su │ │ │ │ └── whs │ │ │ │ └── hyphens │ │ │ │ ├── PatternsBuilder.java │ │ │ │ ├── InputStreamPatternLoader.java │ │ │ │ ├── PatternsLoader.java │ │ │ │ └── HyphenLineBreaker.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── hyphens │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── hyphens │ │ └── ExampleInstrumentedTest.java ├── README.md ├── proguard-rules.pro ├── build.gradle └── deploy.gradle ├── hyphenation-rules ├── .gitignore ├── src │ ├── fr │ │ └── assets │ │ │ └── fr.hyphen.dat │ ├── pt │ │ └── assets │ │ │ └── pt.hyphen.dat │ ├── main │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── hyphenation │ │ │ └── rules │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── hyphenation │ │ └── rules │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── syllabification-parent ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── syllabification │ │ │ └── parent │ │ │ └── LineBreaker.java │ ├── test │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── syllabification │ │ │ └── parent │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── syllabification │ │ └── parent │ │ └── ExampleInstrumentedTest.java ├── README.md ├── proguard-rules.pro └── build.gradle ├── wATLlib ├── wlazydrawable-parent ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── lazydrawable │ │ │ └── parent │ │ │ └── LazyDrawable.java │ ├── test │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── lazydrawable │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── lazydrawable │ │ └── ApplicationTest.java ├── build.gradle └── proguard-rules.pro ├── screenshots ├── aa-s2s.png ├── imageWrap1.png ├── imageWrap2.png ├── TextViewWS1.png ├── newLineMargins.png ├── HyphenTextViewEx1.png ├── HyphenTextViewEx2.png ├── HyphenTextViewEx3.png ├── imageWrapSide2Side.png ├── newLineMarginsPart01.png ├── TextViewExScrollView1.png ├── newLineMarginsPart01Desc.png ├── MultiColumnSamplePhonePortrait.png └── MultiColumnSamplePhoneLandscape.png ├── .gitmodules ├── whsutils ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── su │ │ │ └── whs │ │ │ └── utils │ │ │ ├── ManifestMetadata.java │ │ │ ├── NetUtils.java │ │ │ ├── AndroidUtils.java │ │ │ ├── ZipFileExt.java │ │ │ └── FileUtils.java │ └── androidTest │ │ └── java │ │ └── su │ │ └── whs │ │ └── utils │ │ └── ApplicationTest.java ├── build.gradle └── proguard-rules.pro ├── gradle.properties ├── .gitignore ├── settings.gradle ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── .idea └── runConfigurations.xml └── README.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /htmlparser/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /mediaview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /syllabification/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /hyphenation-rules/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /syllabification-parent/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /wATLlib: -------------------------------------------------------------------------------- 1 | /home/geek/AndroidStudioProjects/Separates/wATLlib -------------------------------------------------------------------------------- /wlazydrawable-parent/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml 3 | /deploy.gradle 4 | -------------------------------------------------------------------------------- /screenshots/aa-s2s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/aa-s2s.png -------------------------------------------------------------------------------- /screenshots/imageWrap1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/imageWrap1.png -------------------------------------------------------------------------------- /screenshots/imageWrap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/imageWrap2.png -------------------------------------------------------------------------------- /app/src/main/assets/nodz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/nodz.gif -------------------------------------------------------------------------------- /app/src/main/ic_real-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/ic_real-web.png -------------------------------------------------------------------------------- /screenshots/TextViewWS1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/TextViewWS1.png -------------------------------------------------------------------------------- /app/src/main/ic_article-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/ic_article-web.png -------------------------------------------------------------------------------- /screenshots/newLineMargins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/newLineMargins.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "watllibrarylite"] 2 | path = wATLlib 3 | url = git@github.com:suwhs/wATLlib.git 4 | -------------------------------------------------------------------------------- /app/src/main/assets/hovercat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/hovercat.gif -------------------------------------------------------------------------------- /screenshots/HyphenTextViewEx1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/HyphenTextViewEx1.png -------------------------------------------------------------------------------- /screenshots/HyphenTextViewEx2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/HyphenTextViewEx2.png -------------------------------------------------------------------------------- /screenshots/HyphenTextViewEx3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/HyphenTextViewEx3.png -------------------------------------------------------------------------------- /screenshots/imageWrapSide2Side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/imageWrapSide2Side.png -------------------------------------------------------------------------------- /screenshots/newLineMarginsPart01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/newLineMarginsPart01.png -------------------------------------------------------------------------------- /app/src/main/assets/top_pane-1.9.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/top_pane-1.9.4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/pinfish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable/pinfish.jpg -------------------------------------------------------------------------------- /screenshots/TextViewExScrollView1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/TextViewExScrollView1.png -------------------------------------------------------------------------------- /whsutils/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | utils 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/assets/articles/SZ_250.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/SZ_250.jpg -------------------------------------------------------------------------------- /app/src/main/assets/game-screen-1.9.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/game-screen-1.9.4.jpg -------------------------------------------------------------------------------- /app/src/main/assets/right_pane-1.9.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/right_pane-1.9.4.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-hdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-hdpi/ic_real.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-mdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-mdpi/ic_real.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xhdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xhdpi/ic_real.png -------------------------------------------------------------------------------- /htmlparser/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | htmlparser 3 | 4 | -------------------------------------------------------------------------------- /mediaview/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | mediaview 3 | 4 | -------------------------------------------------------------------------------- /screenshots/newLineMarginsPart01Desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/newLineMarginsPart01Desc.png -------------------------------------------------------------------------------- /app/src/main/assets/articles/lessonone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/lessonone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/pinfish_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable/pinfish_small.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-hdpi/ic_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-hdpi/ic_columns.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-mdpi/ic_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-mdpi/ic_columns.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxhdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxhdpi/ic_real.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_real.png -------------------------------------------------------------------------------- /syllabification/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | hyphens 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/assets/articles/opto_LIGLUR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/opto_LIGLUR.png -------------------------------------------------------------------------------- /app/src/main/assets/articles/opto_opener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/opto_opener.png -------------------------------------------------------------------------------- /app/src/main/assets/articles/opto_sidebar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/opto_sidebar.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_hyphen.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_justify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_justify.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_hyphen.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_justify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_justify.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_hyphen.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_justify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_justify.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_hyphen.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xhdpi/ic_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xhdpi/ic_columns.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxhdpi/ic_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxhdpi/ic_columns.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_columns.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_hyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_hyphen.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_justify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_justify.png -------------------------------------------------------------------------------- /hyphenation-rules/src/fr/assets/fr.hyphen.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/hyphenation-rules/src/fr/assets/fr.hyphen.dat -------------------------------------------------------------------------------- /hyphenation-rules/src/pt/assets/pt.hyphen.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/hyphenation-rules/src/pt/assets/pt.hyphen.dat -------------------------------------------------------------------------------- /screenshots/MultiColumnSamplePhonePortrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/MultiColumnSamplePhonePortrait.png -------------------------------------------------------------------------------- /app/src/main/assets/articles/market-qr-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/market-qr-code.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_image_wrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_image_wrap.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_image_wrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_image_wrap.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_justify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_justify.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-hdpi/ic_play_button.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-mdpi/ic_play_button.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xhdpi/ic_play_button.png -------------------------------------------------------------------------------- /screenshots/MultiColumnSamplePhoneLandscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/screenshots/MultiColumnSamplePhoneLandscape.png -------------------------------------------------------------------------------- /app/src/main/assets/articles/channelrhodopsin-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/channelrhodopsin-2.gif -------------------------------------------------------------------------------- /app/src/main/assets/articles/kbogla_largecover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/kbogla_largecover.jpg -------------------------------------------------------------------------------- /app/src/main/assets/articles/lessonone-180x300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/lessonone-180x300.png -------------------------------------------------------------------------------- /app/src/main/assets/articles/opto_damagedretina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/opto_damagedretina.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/GamjaFlower-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/fonts/GamjaFlower-Regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_select_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_select_text.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_select_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_select_text.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_image_wrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_image_wrap.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_select_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_select_text.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_image_wrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_image_wrap.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_select_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_select_text.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxhdpi/ic_play_button.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_image_wrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_image_wrap.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_play_button.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_select_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_select_text.png -------------------------------------------------------------------------------- /wlazydrawable-parent/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | wlazydrawable-parent 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/assets/articles/wt_javasparrow_free.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/assets/articles/wt_javasparrow_free.jpg -------------------------------------------------------------------------------- /syllabification-parent/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | syllabification-parent 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_battle_for_wesnoth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-hdpi/ic_battle_for_wesnoth.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_battle_for_wesnoth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-mdpi/ic_battle_for_wesnoth.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battle_for_wesnoth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xhdpi/ic_battle_for_wesnoth.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_battle_for_wesnoth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/drawable-xxhdpi/ic_battle_for_wesnoth.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_battle_for_wesnoth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_battle_for_wesnoth.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.jetifier.blacklist=butterknife-compiler 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | local.properties 3 | *.iml 4 | .idea 5 | deploy.gradle 6 | captures/ 7 | screenshots/ 8 | gradlew 9 | gradle/ 10 | .gradle/ 11 | 12 | -------------------------------------------------------------------------------- /syllabification/src/main/resources/hyphenation-rules/fr.hyphen.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/syllabification/src/main/resources/hyphenation-rules/fr.hyphen.dat -------------------------------------------------------------------------------- /syllabification/src/main/resources/hyphenation-rules/pt.hyphen.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suwhs/wATL/HEAD/syllabification/src/main/resources/hyphenation-rules/pt.hyphen.dat -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':whsutils', ':app', ':wlazydrawable-parent', ':wATLlib', ':wlazydrawable', ':mediaview', ':syllabification', ':syllabification-parent', ':hyphenation-rules' 2 | -------------------------------------------------------------------------------- /app/src/main/res/xml/activity_textview_ws_help.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mediaview/src/main/java/su/whs/mediaview/IMediaView.java: -------------------------------------------------------------------------------- 1 | package su.whs.mediaview; 2 | 3 | /** 4 | * Created by igor n. boulliev on 07.01.17. 5 | */ 6 | public interface IMediaView { 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /whsutils/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Feb 16 10:55:13 MSK 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/ArticleView.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | /** 4 | * Created by igor n. boulliev on 12.06.15. 5 | */ 6 | public interface ArticleView { 7 | void setLoadingState(boolean state, int percents); 8 | void setContent(String title, String author, String source, CharSequence content); 9 | } 10 | -------------------------------------------------------------------------------- /mediaview/src/main/java/su/whs/mediaview/MediaContainer.java: -------------------------------------------------------------------------------- 1 | package su.whs.mediaview; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by igor n. boulliev on 14.01.16. 7 | */ 8 | public interface MediaContainer { 9 | Context getContext(); 10 | void addView(IMediaView mv); 11 | void onMediaViewClosed(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/acitivity_multi_column_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /syllabification/src/main/java/su/whs/hyphens/PatternsBuilder.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphens; 2 | 3 | /** 4 | * Created by igor n. boulliev on 14.01.17. 5 | */ 6 | 7 | public class PatternsBuilder { 8 | String URL = "http://tug.org/svn/texhyphen/trunk/collaboration/repository/hyphenator/%s.js?view=co&content-type=text%2Fplain"; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /htmlparser/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /mediaview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /syllabification/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /hyphenation-rules/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /wlazydrawable-parent/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /syllabification-parent/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_about.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /wlazydrawable-parent/src/test/java/su/whs/lazydrawable/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.lazydrawable; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/su/whs/watl/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_articles_flow.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_text_view_w.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /whsutils/src/androidTest/java/su/whs/utils/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.utils; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_hyphen_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_multi_column_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_another_hyphen_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /wlazydrawable-parent/src/androidTest/java/su/whs/lazydrawable/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.lazydrawable; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /wlazydrawable-parent/src/main/java/su/whs/lazydrawable/parent/LazyDrawable.java: -------------------------------------------------------------------------------- 1 | package su.whs.lazydrawable.parent; 2 | 3 | import android.graphics.drawable.Drawable; 4 | 5 | /** 6 | * Created by igor n. boulliev on 18.08.16. 7 | */ 8 | public interface LazyDrawable { 9 | public abstract void Unload(); 10 | public abstract void onVisibilityChanged(boolean visible); 11 | public abstract void load(); 12 | public abstract void setCallbackCompat(Drawable.Callback drawableCallbacks); 13 | } 14 | -------------------------------------------------------------------------------- /mediaview/src/test/java/su/whs/mediaview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.mediaview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /htmlparser/src/test/java/su/whs/htmlparser/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.htmlparser; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /syllabification/src/test/java/su/whs/hyphens/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphens; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /hyphenation-rules/src/test/java/su/whs/hyphenation/rules/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphenation.rules; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/values/help.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sample TextViewWS - derived from android.viewTextView 5 | 6 | 7 | sample TextViewEx - full text justify 8 | 9 | 10 | sample TextViewEx - full text justify and hyphenation example 11 | 12 | 13 | sample MultiColumnTextViewEx 14 | 15 | -------------------------------------------------------------------------------- /syllabification-parent/src/test/java/su/whs/syllabification/parent/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.syllabification.parent; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/TaggedBitmapDrawable.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.content.res.Resources; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.BitmapDrawable; 6 | 7 | /** 8 | * Created by igor n. boulliev on 02.09.15. 9 | */ 10 | public class TaggedBitmapDrawable extends BitmapDrawable { 11 | private String mTag; 12 | public TaggedBitmapDrawable(Resources res, Bitmap bitmap, String tag) { 13 | super(res,bitmap); 14 | mTag = tag; 15 | } 16 | 17 | public String getTag() { return mTag; } 18 | } 19 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_another_hyphen_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /syllabification/README.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Copyright 2015 whs.su 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_articles_flow.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /syllabification-parent/README.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Copyright 2015 whs.su 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /wlazydrawable-parent/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | api fileTree(dir: 'libs', include: ['*.jar']) 23 | testApi 'junit:junit:4.12' 24 | } 25 | 26 | apply from: 'deploy.gradle' -------------------------------------------------------------------------------- /whsutils/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | defaultConfig { 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | } 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | 19 | useLibrary 'org.apache.http.legacy' 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(dir: 'libs', include: ['*.jar']) 24 | // api 'com.android.support:appcompat-v7:28.0.0' 25 | } 26 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /htmlparser/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /mediaview/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /whsutils/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /syllabification/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /hyphenation-rules/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /wlazydrawable-parent/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /syllabification-parent/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/geek/Downloads/adt-bundle-linux-x86_64-20140702/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /syllabification/src/main/java/su/whs/hyphens/InputStreamPatternLoader.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphens; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * Created by igor n. boulliev on 13.01.17. 9 | */ 10 | public class InputStreamPatternLoader { 11 | public HyphenPattern getHyphenPattern(String fileName) { 12 | return getHyphenPatternInputStream(getClass().getResourceAsStream(fileName)); 13 | } 14 | 15 | public HyphenPattern getHyphenPatternInputStream(InputStream inputStream) { 16 | try { 17 | DataInputStream in = new DataInputStream(inputStream); 18 | return new HyphenPattern(in); 19 | } catch (IOException e) { 20 | return null; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /htmlparser/src/androidTest/java/su/whs/htmlparser/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.htmlparser; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("su.whs.htmlparser.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mediaview/src/androidTest/java/su/whs/mediaview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.mediaview; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("su.whs.mediaview.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /syllabification-parent/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | defaultConfig { 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | api fileTree(dir: 'libs', include: ['*.jar']) 25 | androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | testApi 'junit:junit:4.12' 29 | } 30 | 31 | apply from: 'deploy.gradle' -------------------------------------------------------------------------------- /hyphenation-rules/src/androidTest/java/su/whs/hyphenation/rules/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphenation.rules; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("su.whs.hyphenation.rules.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /syllabification-parent/src/androidTest/java/su/whs/syllabification/parent/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.syllabification.parent; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("su.whs.syllabification.parent.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 8 | 12 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_text_view_ws.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /htmlparser/src/main/java/su/whs/htmlparser/Html.java: -------------------------------------------------------------------------------- 1 | package su.whs.htmlparser; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.text.Editable; 5 | import android.text.Spanned; 6 | 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by igor n. boulliev on 23.01.17. 11 | */ 12 | 13 | public class Html { 14 | 15 | public interface HtmlTagHandler { 16 | void onTagStart(String tag, Map attributes, Editable output); 17 | void onTagEnd(String tag, Editable output); 18 | } 19 | 20 | public interface DrawableHandler { 21 | Drawable getDrawable(String url, String mimeType, Map attributes); 22 | } 23 | 24 | static { 25 | System.loadLibrary("htmlparser"); 26 | } 27 | 28 | public native Spanned fromHtml(String html); 29 | public native Spanned fromHtml(HtmlTagHandler tagHandler); 30 | public native Spanned fromHtml(HtmlTagHandler tagHandler, DrawableHandler drawableHandler); 31 | } 32 | -------------------------------------------------------------------------------- /syllabification/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | defaultConfig { 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(include: ['*.jar'], dir: 'libs') 25 | androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | testApi 'junit:junit:4.12' 29 | // compile project(':syllabification-parent') 30 | api 'su.whs:syllabification-parent:1.3' 31 | } 32 | 33 | apply from: 'deploy.gradle' -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | watl 3 | wATL Demo 4 | Settings 5 | TextViewWS 6 | Justification 7 | Hyphenation 8 | Image Wrap 9 | About 10 | Paginated Article 11 | 12 | Hello world! 13 | About 14 | MultiColumn Sample 15 | 16 | Usual TextView with selection support 17 | Large List 18 | 19 | -------------------------------------------------------------------------------- /mediaview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | defaultConfig { 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(dir: 'libs', include: ['*.jar']) 25 | androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | // api 'com.android.support:appcompat-v7:28.0.0' 29 | testApi 'junit:junit:4.12' 30 | // api 'com.android.support:appcompat-v7:28.0.0' 31 | api 'su.whs:wlazydrawable-parent:1.0.0' 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/assets/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

About
wATL Demo App

4 |

5 |

6 | version 1.2.2 7 |

8 |

9 |

Welcome!

10 |

11 |

This is wATL library demo application, shows some features of TextViewEx - drop-in 12 | replacement for standart android.view.TextView with some additional features: 13 |

    14 |
  • full text justification
  • 15 |
  • image wrap
  • 16 |
  • hyphenation supports
  • 17 |
  • supports animation DynamicDrawableSpan
  • 18 |
  • experimental support for bidirectional text
  • 19 |
  • pagination adapter
  • 20 |
21 |

22 | 23 |
24 |
25 |

wATL Home

26 |
27 | 28 |

sales@whs.su

29 |

support@whs.su

30 |
31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_hyphen_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /hyphenation-rules/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | defaultConfig { 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | 16 | productFlavors { 17 | en_us { 18 | } 19 | 20 | ru { 21 | } 22 | 23 | fr { 24 | } 25 | 26 | pt { 27 | } 28 | } 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | } 36 | 37 | dependencies { 38 | implementation fileTree(dir: 'libs', include: ['*.jar']) 39 | androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', { 40 | exclude group: 'com.android.support', module: 'support-annotations' 41 | }) 42 | testApi 'junit:junit:4.12' 43 | } 44 | 45 | 46 | apply from: 'deploy.gradle' -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_multi_column_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/activity_multi_column_text_view_ex.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /htmlparser/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | flavorDimensions 'default' 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | debug { 21 | jniDebuggable true 22 | } 23 | } 24 | 25 | externalNativeBuild { 26 | cmake { 27 | path "src/main/jni/CMakeLists.txt" 28 | } 29 | } 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(include: ['*.jar'], dir: 'libs') 34 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 35 | exclude group: 'com.android.support', module: 'support-annotations' 36 | }) 37 | // api 'com.android.support:appcompat-v7:28.0.0' 38 | testApi 'junit:junit:4.12' 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/samples_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 15 | 16 | 22 | 23 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /whsutils/src/main/java/su/whs/utils/ManifestMetadata.java: -------------------------------------------------------------------------------- 1 | package su.whs.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.PackageManager.NameNotFoundException; 7 | import android.os.Bundle; 8 | 9 | /** 10 | * 11 | * @author igor n. boulliev 12 | * 13 | * read metadata from manifest 14 | * 15 | */ 16 | 17 | public class ManifestMetadata { 18 | /** 19 | * 20 | * @param context 21 | * @param key - meta-data name 22 | * @return string value 23 | */ 24 | public static String getMetadata(Context context, String key) { 25 | Bundle bundle = all(context); 26 | if (bundle.containsKey(key)) 27 | return bundle.getString(key); 28 | return null; 29 | } 30 | 31 | /** 32 | * 33 | * @param context 34 | * @return Bundle with all application's meta-data key-value pairs 35 | * 36 | */ 37 | 38 | public static Bundle all(Context context) { 39 | ApplicationInfo ai; 40 | try { 41 | ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); 42 | } catch (NameNotFoundException e) { 43 | return null; 44 | } 45 | Bundle bundle = ai.metaData; 46 | return bundle; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/res/menu/text_options.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_text_view_ex_scroll.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 14 | 15 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_text_view_ex_scroll.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | 10 | 12 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /whsutils/src/main/java/su/whs/utils/NetUtils.java: -------------------------------------------------------------------------------- 1 | package su.whs.utils; 2 | 3 | import android.util.Log; 4 | 5 | import org.apache.http.HttpEntity; 6 | import org.apache.http.HttpResponse; 7 | import org.apache.http.client.HttpClient; 8 | import org.apache.http.client.methods.HttpGet; 9 | import org.apache.http.impl.client.DefaultHttpClient; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.net.URI; 14 | 15 | /** 16 | * Created by igor n. boulliev on 04.05.15. 17 | */ 18 | public class NetUtils { 19 | public interface Result { 20 | void onError(int errorCode); 21 | void onSuccess(InputStream is); 22 | } 23 | public static InputStream HttpGet(URI url, Result result) { 24 | HttpClient hc = new DefaultHttpClient(); 25 | HttpGet hg = new HttpGet(url); 26 | try { 27 | HttpResponse r = hc.execute(hg); 28 | HttpEntity e = r.getEntity(); 29 | if (result!=null && e!=null) 30 | result.onSuccess(e.getContent()); 31 | return e.getContent(); 32 | } catch (IOException e) { 33 | if (result!=null) { 34 | result.onError(-1); 35 | } 36 | } catch (SecurityException e) { 37 | Log.e("NetUtils", "NetUtils require INTERNET permission "); 38 | } 39 | 40 | return null; 41 | } 42 | 43 | public static InputStream HttpGet(URI url) { 44 | return HttpGet(url,null); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/TextPager.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import androidx.core.view.ViewPager; 7 | import android.util.AttributeSet; 8 | 9 | /** 10 | * Created by igor n. boulliev on 18.06.15. 11 | */ 12 | public class TextPager extends ViewPager { 13 | 14 | public TextPager(Context context) { 15 | super(context); 16 | } 17 | 18 | public TextPager(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | private Handler handler = new Handler() 23 | { 24 | public void handleMessage(Message msg) 25 | { 26 | switch(msg.what) 27 | { 28 | case 0: 29 | _invalidatePageTransformer(); 30 | break; 31 | } 32 | } 33 | }; 34 | 35 | private void _invalidatePageTransformer() 36 | { 37 | //no need to invalidate if we have no adapter or no items 38 | if (this.getAdapter() != null && this.getAdapter().getCount() > 0) 39 | { 40 | //import check here, only fakeDrag if "beginFakeDrag()" returns true 41 | if (this.beginFakeDrag()) 42 | { 43 | this.fakeDragBy(0f); 44 | this.endFakeDrag(); 45 | } 46 | } 47 | } 48 | 49 | public void sendInvalidatePageTransformer() 50 | { 51 | this.handler.sendEmptyMessage(0); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | signingConfigs { 5 | config { 6 | keyAlias 'watl' 7 | storeFile file('${System.properties[\'user.home\']}/AndroidStudioProjects/watldemo.keystore') 8 | } 9 | } 10 | 11 | compileSdkVersion 23 12 | buildToolsVersion '25.0.0' 13 | defaultConfig { 14 | applicationId "su.whs.watl.samples" 15 | minSdkVersion 14 16 | targetSdkVersion 23 17 | versionCode 8 18 | versionName "1.2.2" 19 | signingConfig signingConfigs.config 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | signingConfig signingConfigs.config 26 | } 27 | debug { 28 | } 29 | } 30 | productFlavors { 31 | } 32 | } 33 | 34 | dependencies { 35 | compile fileTree(include: ['*.jar'], dir: 'libs') 36 | // compile 'com.android.support:appcompat-v7:23.4.0' 37 | // compile project(':wlazydrawable') 38 | compile project(':wATLlib') 39 | compile project(':whsutils') 40 | compile 'androidx.legacy:legacy-support-v4:1.0.0' 41 | compile 'pl.droidsonroids.gif:android-gif-drawable:1.1.+' 42 | //compile 'su.whs:wATLlib:1.2.3.2' 43 | compile 'androidx.recyclerview:recyclerview:1.0.0' 44 | compile 'su.whs:wlazydrawable:1.0.1' 45 | compile project(':syllabification') 46 | // compile 'su.whs:syllabification:1.3' 47 | } 48 | -------------------------------------------------------------------------------- /syllabification/src/main/java/su/whs/hyphens/PatternsLoader.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphens; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.util.Log; 6 | 7 | import java.io.IOException; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * Created by igor n. boulliev on 10.04.15. 13 | */ 14 | 15 | public class PatternsLoader extends InputStreamPatternLoader { 16 | private static final String TAG = "PatternsLoader"; 17 | private static PatternsLoader mInstance = null; 18 | private Map mCache = new HashMap(); 19 | private PatternsLoader() {} 20 | 21 | 22 | public static PatternsLoader getInstance() { 23 | synchronized (PatternsLoader.class) { 24 | if (mInstance == null) 25 | mInstance = new PatternsLoader(); 26 | } 27 | return mInstance; 28 | } 29 | 30 | public HyphenPattern getHyphenPatternAssets(Context context, String fileName) { 31 | synchronized (mCache) { 32 | if (mCache.containsKey(fileName)) 33 | return mCache.get(fileName); 34 | AssetManager am = context.getAssets(); 35 | if (am != null) { 36 | try { 37 | HyphenPattern hyphenPattern = getHyphenPatternInputStream(am.open(fileName)); 38 | if (hyphenPattern == null) 39 | return null; 40 | mCache.put(fileName,hyphenPattern); 41 | } catch (IOException e) { 42 | Log.e(TAG, "Error loading hyphenation rules:" + e); 43 | return null; 44 | } 45 | } 46 | return mCache.get(fileName); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /whsutils/src/main/java/su/whs/utils/AndroidUtils.java: -------------------------------------------------------------------------------- 1 | package su.whs.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.drawable.BitmapDrawable; 8 | import android.graphics.drawable.Drawable; 9 | 10 | public class AndroidUtils { 11 | /* resolve resource id from string '@id/name' */ 12 | public static int resolveId(Context context, Resources res, String string) { 13 | if (string.startsWith("@")) { 14 | String subs = string.substring(1, string.length()); 15 | String[] parts = subs.split("/"); 16 | if (parts[0].startsWith("+")) 17 | parts[0] = parts[0].substring(1); 18 | return res.getIdentifier(parts[1], parts[0], context 19 | .getPackageName()); 20 | 21 | } 22 | return Integer.parseInt(string); 23 | } 24 | 25 | public static String resolveString(Context context, Resources res, String string) { 26 | if (string.startsWith("@")) { 27 | String subs = string.substring(1, string.length()); 28 | String[] parts = subs.split("/"); 29 | int id = res.getIdentifier(parts[1], parts[0], context 30 | .getPackageName()); 31 | if (id == 0x0) { 32 | return string; 33 | } 34 | return res.getString(id); 35 | } 36 | return string; 37 | } 38 | 39 | public static Drawable getRotateDrawable(Resources res, final Bitmap bitmap, final float angle) { 40 | final BitmapDrawable drawable = new BitmapDrawable(res, bitmap) { 41 | @Override 42 | public void draw(final Canvas canvas) { 43 | canvas.save(); 44 | canvas.rotate(angle, bitmap.getWidth() / 2, bitmap.getHeight() / 2); 45 | super.draw(canvas); 46 | canvas.restore(); 47 | } 48 | }; 49 | return drawable; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/records_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 27 | 28 | 39 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | wATL library Demo sources 2 | ========== 3 | 4 | NB: library itself hosted now in separate repository - github.com/suwhs/wATLlib 5 | 6 | License 7 | ========= 8 | APACHE LICENSE 2.0 9 | 10 | Description 11 | ====== 12 | *wATL* is a library for android applications with features: 13 | - formatted text full justification, 14 | - wrap text around images, 15 | - auto-hyphenation, 16 | - adapter for show paginated article with stock ViewPager 17 | - supported Android version - 2.3 - 5.1+ (both runtimes - ART and DALVIK) 18 | 19 | 20 | Demo Application available on Google Play 21 | 22 | 23 | Get it on Google Play 24 | 25 | 26 | [![Demo Video on Youtube](http://img.youtube.com/vi/ZtXvyS6GHGo/0.jpg)](https://youtu.be/ZtXvyS6GHGo) 27 | 28 | 29 | Quick Start 30 | ====== 31 | Usage: 32 | 33 | wATLlib published on jcenter repository, so just 34 | 35 | add to dependencies : 36 | ```gradle 37 | compile 'su.whs:wATLlib:1.1.7a' 38 | ``` 39 | 40 | 41 | Published Classes 42 | ======== 43 | 44 | some description on Wiki 45 | 46 | - *su.whs.watl.ui.TextViewWS* - base class with methods for handling text selection 47 | screenshot 1 48 | - *su.whs.watl.ui.ClickableSpanListener* - interface for easy handle clicks on drawable 49 | onClick() method receive view, span position, and coordinates of image within view 50 | 51 | - *su.whs.watl.ui.TextViewEx* - class (replacement for stock TextView) with full text justification support (enabled by default) 52 | screenshot 2 53 | 54 | 55 | Contacts 56 | ======== 57 | wATL Home
58 | info@whs.su 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /syllabification-parent/src/main/java/su/whs/syllabification/parent/LineBreaker.java: -------------------------------------------------------------------------------- 1 | package su.whs.syllabification.parent; 2 | 3 | /** 4 | * 5 | * 6 | * @author igor n. boulliev 7 | * Apache License 2.0 8 | * 9 | */ 10 | 11 | public class LineBreaker { 12 | /** 13 | * LineBreaker interface 14 | * 15 | * @param text 16 | * @param start 17 | * @param end 18 | * @return type and position of linebreak between start and end NOTE: position of 19 | * last character at the line 20 | */ 21 | 22 | public static final int HYPHEN = 0xf0000000; 23 | 24 | public static int getPosition(int value) { 25 | return value & 0x0fffffff; 26 | } 27 | 28 | public static boolean isHyphen(int value) { 29 | return (value & HYPHEN) == HYPHEN; 30 | } 31 | 32 | /* punctuation ranges */ 33 | // 20-3f 34 | // 5b-60 35 | // 7b-7e 36 | 37 | /* 38 | 39 | if (c >= 0x0600 && c <=0x06E0) 40 | 41 | } 42 | */ 43 | 44 | public static boolean isLetter(char ch) { 45 | /* 0x0600-0x06e0 - arabic */ 46 | return Character.isLetter(ch) || (ch >=0x0600 && ch<= 0x06e0); 47 | } 48 | 49 | public static boolean isPunktuation(char ch) { 50 | return !isLetter(ch) && ch < 0x7e && 51 | (ch > 0x20 && 52 | (ch < 0x40 || 53 | (ch > 0x5b && 54 | (ch < 0x60 || 55 | ch > 0x7e)))); 56 | } 57 | 58 | public int nearestLineBreak(char[] text, int start, int _end, int limit) { 59 | int end = _end; 60 | 61 | for (; end >= start; end--) { 62 | if (text[end] == ' ' || text[end] == ',' || text[end] == '.' || text[end] == '!' || text[end] == '-' || text[end] == '?') 63 | break; 64 | } 65 | if ((end > start - 1) && end < limit && Character.isLetter(text[end]) && Character.isLetter(text[end + 1])) 66 | end = end | HYPHEN; 67 | return end; // force break, if not fit 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/TextViewWSActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.graphics.Typeface; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import androidx.appcompat.app.ActionBarActivity; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | import su.whs.watl.ui.TextViewWS; 11 | 12 | 13 | public class TextViewWSActivity extends ActionBarActivity implements ArticleView { 14 | private static final String TAG="TextViewWS.Demo"; 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_text_view_ws); 19 | ((wATLApp)getApplication()).getArticle(ContentLoader.ARTICLE_SCIENCE2, this); 20 | } 21 | 22 | @Override 23 | public boolean onCreateOptionsMenu(Menu menu) { 24 | // Inflate the menu; this adds items to the action bar if it is present. 25 | getMenuInflater().inflate(R.menu.menu_text_view_w, menu); 26 | return true; 27 | } 28 | 29 | @Override 30 | public boolean onOptionsItemSelected(MenuItem item) { 31 | // Handle action bar item clicks here. The action bar will 32 | // automatically handle clicks on the Home/Up button, so long 33 | // as you specify a parent activity in AndroidManifest.xml. 34 | int id = item.getItemId(); 35 | 36 | //noinspection SimplifiableIfStatement 37 | if (id == R.id.action_settings) { 38 | return true; 39 | } 40 | 41 | return super.onOptionsItemSelected(item); 42 | } 43 | 44 | @Override 45 | public void setLoadingState(boolean state, int percents) { 46 | 47 | } 48 | 49 | @Override 50 | public void setContent(String title, String author, String source, CharSequence content) { 51 | TextViewWS tv = (TextViewWS) findViewById(R.id.textView); 52 | Typeface font = Typeface.createFromAsset(tv.getContext().getAssets(), "fonts/GamjaFlower-Regular.ttf"); 53 | tv.setTypeface(font); 54 | tv.setText(content); 55 | 56 | tv.setTextIsSelectable(true); 57 | if (Build.VERSION.SDK_INT > 10) 58 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_recycler_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 20 | 25 | 30 | 36 | 42 | 43 | 44 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /syllabification/deploy.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | apply plugin: 'com.jfrog.bintray' 3 | 4 | def siteUrl = 'http://whs.su' // Homepage URL of the library 5 | def gitUrl = 'https://github.com/suwhs/wATL.git' // Git repository URL 6 | // Maven Group ID for the artifact 7 | version='1.3' 8 | group='su.whs' 9 | 10 | install { 11 | repositories.mavenInstaller { 12 | // repository(url: "file://${System.properties['user.home']}/AndroidStudioProjects/maven-repository") 13 | pom.project { 14 | packaging 'aar' 15 | groupId 'su.whs' 16 | artifactId 'syllabification' 17 | version '1.3' 18 | name 'syllabification' 19 | url siteUrl 20 | inceptionYear '2016' 21 | licenses { 22 | license { 23 | name 'Apache License 2.0' 24 | url 'http://www.apache.org/licenses/LICENSE-2.0' 25 | distribution 'repo' 26 | } 27 | 28 | } 29 | scm { 30 | connection gitUrl 31 | developerConnection gitUrl 32 | url siteUrl 33 | } 34 | } 35 | } 36 | } 37 | 38 | Properties properties = new Properties() 39 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 40 | 41 | bintray { 42 | user = properties.getProperty("bintray.user") 43 | key = properties.getProperty("bintray.apikey") 44 | 45 | configurations = ['archives','javadocDeps'] 46 | pkg { 47 | repo = "maven" 48 | name = "syllabification" 49 | websiteUrl = siteUrl 50 | vcsUrl = gitUrl 51 | licenses = ["Apache-2.0"] 52 | publish = true 53 | } 54 | } 55 | 56 | 57 | task sourcesJar(type: Jar) { 58 | from android.sourceSets.main.java.srcDirs 59 | classifier = 'sources' 60 | } 61 | 62 | task javadoc(type: Javadoc) { 63 | source = android.sourceSets.main.java.srcDirs 64 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 65 | failOnError false 66 | } 67 | 68 | task javadocJar(type: Jar, dependsOn: javadoc) { 69 | classifier = 'javadoc' 70 | from javadoc.destinationDir 71 | // options.encoding = 'UTF-8' 72 | } 73 | 74 | artifacts { 75 | archives javadocJar 76 | archives sourcesJar 77 | } 78 | 79 | -------------------------------------------------------------------------------- /app/src/main/assets/articles/rtl_test_2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eros ipsum, dictum nec neque et, facilisis gravida dolor. Morbi mi sem, laoreet ac volutpat at, vehicula eget nibh. Mauris velit elit, iaculis in auctor id, fringilla non diam. Sed vehicula nisi neque, at vulputate arcu vulputate nec.

5 |

عل حول يرتبط القوى مقاطعة. ضرب معزّزة المنتصر الألماني إذ. تم دنو بشرية ويتّفق والبريطاني, وشعار وفنلندا الأوروبي مع حتى, يكن قد هُزم البشريةً. عل خطّة وحتى بالدبابات تلك, حول ماذا الأولية العسكرية عن.

 

الى ألمّ الأوروبية، عل, نورماندي لبولندا، انه لم, جوي إحتلال بالمحور لم.

شمال بانتحار العمليات تعد عل, جوي إذ اللا جحافل العام, بعد وأكثرها التجارية ما. و جدول النازي واستمرت

 

هذه, لم هاربر للحرب الشمل لان. سمّي الصين الولايات تم بها. أخذ مع لأداء والحلفاء, إذ وفي خطّة إخضاع الرئيسية, المواد الإتفاقية السوفييتي أضف تم. بها وقامت لألمانيا أي, شمال غريمه أم تلك, أي بين أمّا لقوات مواقعها.

6 |

7 | Quisque id enim congue, ullamcorper felis aliquam, sodales nisi. Duis ligula lectus, efficitur vel tristique eget, volutpat vitae nisi. 8 | 9 | كرسي العظمى ذلك قد. مسرح لدحر الأوروبيّون أم بحق, الضغوط والبريطاني قد كان, مع بعض الأجل بمباركة 10 |

11 |

12 | Ut vel urna tristique, scelerisque felis vel, fringilla erat. Fusce dignissim quam nec nunc feugiat varius. Etiam egestas iaculis elit, at porttitor elit dapibus nec. 13 | واستمرت. وحزبه وأكثرها قهر ان. جعل كل مهمّات الخاسر التاريخ،, لم انه دارت صفحة غريمه, و ذات أفاق أواخر استدعى. الخاصّة الياباني السوفييتية عل ومن, خصوصا المحور والمانيا وضم أن, الجنود بأضرار و تحت. وتقهقر العمليات مكن عن, والديون المجتمع البشريةً ثم دنو.
14 | 15 | Etiam turpis enim, ornare convallis placerat eget, commodo vel erat. سابق أساسي تغييرات لم أما. غزو الدول هيروشيما أم, حين أصقاع الأحمر العالمي إذ, أحدث وبعدما واقتصار عن هذا. فسقط العمليات بحق لم, من قبضتهم الهادي وقد. أضف أن الأولى إستسلاماً. هو صفحة أحكم مشروط ربع, دار السبب أسلحته بالرّغم مع. كلّ تاريخ لهيمنة نورمبرغ أي. 16 |

17 |

18 | قط من جحافل الإمبراطورية, الذرية تكاليف ومن بـ, الحزب كنقطة ثم دار. للغزو، الإيطالية إذ ربع, قِبل وأسرت وتم من. حيث بلاده الحدود للسيطرة كل, عل للحرب أوكيناوا أضف. مع الا يذكر ٢٠٠٤ واعتلاء, لم وفي سقطت الحروب. عل كان ماذا القوى, ربع بـ عقبت وقدّموا المقيتة, أن مشارف الطرفين شبح. الجوي الدمج عسكرياً كل يتم. الأعمال القوقازية والبريطاني أن عام. 19 |

20 | 21 | -------------------------------------------------------------------------------- /syllabification/src/main/java/su/whs/hyphens/HyphenLineBreaker.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphens; 2 | 3 | /** 4 | * 5 | * 6 | * @author igor n. boulliev 7 | * Apache License 2.0 8 | * 9 | */ 10 | 11 | import android.annotation.SuppressLint; 12 | import android.content.Context; 13 | import android.util.Log; 14 | 15 | import java.util.HashMap; 16 | 17 | import su.whs.syllabification.parent.LineBreaker; 18 | 19 | import static android.content.ContentValues.TAG; 20 | 21 | 22 | @SuppressLint("UseSparseArrays") 23 | public class HyphenLineBreaker extends LineBreaker { 24 | 25 | private static final HashMap cached; 26 | private ReverseLookupHyphenator mHyphenator; 27 | 28 | static { 29 | cached = new HashMap(); 30 | } 31 | 32 | public HyphenLineBreaker(HyphenPattern pattern) { 33 | mHyphenator = new ReverseLookupHyphenator(pattern); 34 | } 35 | 36 | public static LineBreaker getInstance(HyphenPattern hyphenationPattern) { 37 | if (hyphenationPattern == null) return new DefaultLineBreaker(); 38 | synchronized (cached) { 39 | if (!cached.containsKey(hyphenationPattern)) { 40 | cached.put(hyphenationPattern, new HyphenLineBreaker(hyphenationPattern)); 41 | return cached.get(hyphenationPattern); 42 | } 43 | return cached.get(hyphenationPattern); 44 | } 45 | } 46 | 47 | 48 | public static LineBreaker getInstance(Context context, String name) { 49 | HyphenPattern pat = PatternsLoader.getInstance().getHyphenPatternAssets(context, name + ".hyphen.dat"); 50 | return getInstance(pat); 51 | } 52 | 53 | public static void require(Context context, String... names) { 54 | HyphenPattern pat; 55 | for (String name : names) { 56 | pat = PatternsLoader.getInstance() 57 | .getHyphenPatternAssets(context, name + ".hyphen.dat"); 58 | if (pat == null) { 59 | Log.w(TAG, "COULD NOT FIND REQUIRED '" + name + ".hyphen.dat"); 60 | } else 61 | Log.d(TAG, "loaded: '" + name + "' pattern"); 62 | } 63 | } 64 | 65 | @Override 66 | public int nearestLineBreak(char[] text, int start, int end, int limit) { 67 | int result = mHyphenator.nearestLineBreak(text, start, end, limit) - 1; // correct to wATLlib compatibility prior to 1.4 68 | return result; 69 | } 70 | 71 | private static class DefaultLineBreaker extends LineBreaker { 72 | @Override 73 | public int nearestLineBreak(char[] text, int start, int end, int limit) { 74 | return start; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/SampleActionModeCallback.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.ClipData; 5 | import android.content.ClipboardManager; 6 | import android.content.Context; 7 | import android.os.Build; 8 | import android.view.ActionMode; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.widget.Toast; 12 | 13 | import su.whs.watl.ui.TextViewWS; 14 | 15 | /** 16 | * Created by igor n. boulliev on 15.02.15. 17 | * copy-n-paste from http://stackoverflow.com/questions/22832123/get-selected-text-from-textview 18 | */ 19 | 20 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 21 | public class SampleActionModeCallback implements ActionMode.Callback { 22 | public TextViewWS mTextView = null; 23 | 24 | public SampleActionModeCallback(TextViewWS textView) { 25 | mTextView = textView; 26 | } 27 | 28 | @Override 29 | public boolean onCreateActionMode(ActionMode mode, Menu menu) { 30 | // menu.add(0, DEFINITION, 0, "Definition").setIcon(R.drawable.ic_action_book); 31 | menu.add(0, android.R.id.copy, 0, "copy").setIcon(R.drawable.ic_action_name); 32 | return true; 33 | } 34 | 35 | @Override 36 | public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 37 | // Remove the "select all" option 38 | menu.removeItem(android.R.id.selectAll); 39 | // Remove the "cut" option 40 | menu.removeItem(android.R.id.cut); 41 | // Remove the "copy all" option 42 | // menu.removeItem(android.R.id.copy); 43 | return true; 44 | } 45 | 46 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 47 | @Override 48 | public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 49 | switch (item.getItemId()) { 50 | case android.R.id.copy: 51 | CharSequence text = mTextView.getText().subSequence(mTextView.getSelectionStart(), mTextView.getSelectionEnd()); 52 | ClipboardManager manager = (ClipboardManager) mTextView.getContext().getSystemService(Context.CLIPBOARD_SERVICE); 53 | manager.setPrimaryClip(ClipData.newPlainText(null, text)); 54 | mTextView.setSelected(false); 55 | Toast.makeText(mTextView.getContext(),"Text copied to clipboard",Toast.LENGTH_LONG).show(); 56 | mode.finish(); 57 | return true; 58 | default: 59 | break; 60 | } 61 | return false; 62 | } 63 | 64 | @Override 65 | public void onDestroyActionMode(ActionMode mode) { 66 | mTextView.setTextIsSelectable(false); 67 | mTextView.setTextIsSelectable(true); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/article_page_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 20 | 21 | 28 | 29 | 38 | 39 | 47 | 48 | 49 | 50 | 61 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/GifDrawableCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 whs.su 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package su.whs.watl.samples; 16 | 17 | import android.graphics.Bitmap; 18 | import android.graphics.Canvas; 19 | import android.graphics.ColorFilter; 20 | import android.graphics.Paint; 21 | import android.graphics.PixelFormat; 22 | import android.graphics.Rect; 23 | import android.graphics.drawable.Animatable; 24 | import android.graphics.drawable.Drawable; 25 | import android.os.SystemClock; 26 | 27 | import java.io.InputStream; 28 | 29 | import su.whs.watl.samples.utils.GifDecoder; 30 | 31 | /** 32 | * Created by igor n. boulliev on 01.09.15. 33 | */ 34 | public class GifDrawableCompat extends Drawable implements Animatable { 35 | private GifDecoder mDecoder; 36 | private Bitmap mFrame; 37 | private boolean mStarted = false; 38 | private Paint mPaint = new Paint(); 39 | private Rect mSrcRect = new Rect(); 40 | 41 | private Runnable updateRunable = new Runnable() { 42 | @Override 43 | public void run() { 44 | nextFrame(); 45 | if (mStarted) 46 | scheduleSelf(updateRunable, SystemClock.uptimeMillis()+mDecoder.getNextDelay()); 47 | } 48 | }; 49 | 50 | public GifDrawableCompat(InputStream inputStream) { 51 | mDecoder = new GifDecoder(); 52 | mDecoder.read(inputStream,0); 53 | mDecoder.advance(); 54 | mFrame = mDecoder.getNextFrame(); 55 | mSrcRect.set(0,0,mFrame.getWidth(),mFrame.getHeight()); 56 | } 57 | 58 | @Override 59 | public int getIntrinsicWidth() { return mSrcRect.width(); } 60 | 61 | @Override 62 | public int getIntrinsicHeight() { return mSrcRect.height(); } 63 | 64 | private void nextFrame() { 65 | mDecoder.advance(); 66 | mFrame = mDecoder.getNextFrame(); 67 | invalidateSelf(); 68 | } 69 | 70 | @Override 71 | public void start() { 72 | mStarted = true; 73 | scheduleSelf(updateRunable,SystemClock.uptimeMillis()+mDecoder.getNextDelay()); 74 | } 75 | 76 | @Override 77 | public void stop() { 78 | unscheduleSelf(updateRunable); 79 | mStarted = false; 80 | } 81 | 82 | @Override 83 | public boolean isRunning() { 84 | return mStarted; 85 | } 86 | 87 | @Override 88 | public void draw(Canvas canvas) { 89 | canvas.drawBitmap(mFrame,mSrcRect,getBounds(),mPaint); 90 | } 91 | 92 | @Override 93 | public void setAlpha(int alpha) { 94 | mPaint.setAlpha(alpha); 95 | } 96 | 97 | @Override 98 | public void setColorFilter(ColorFilter cf) { 99 | mPaint.setColorFilter(cf); 100 | } 101 | 102 | @Override 103 | public int getOpacity() { 104 | return PixelFormat.TRANSPARENT; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /whsutils/src/main/java/su/whs/utils/ZipFileExt.java: -------------------------------------------------------------------------------- 1 | package su.whs.utils; 2 | 3 | /** 4 | * Created by igor n. boulliev on 02.05.15. 5 | */ 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.ArrayList; 11 | import java.util.Enumeration; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.zip.ZipEntry; 16 | import java.util.zip.ZipFile; 17 | 18 | /** 19 | * reads zip content tree into cache for fast access 20 | */ 21 | 22 | public class ZipFileExt { 23 | 24 | private class Entry { 25 | public String mName; 26 | public String mPath; 27 | public ZipEntry mEntry; 28 | public List mEntries = null; 29 | 30 | public Entry(String name, ZipEntry entry) { 31 | File f = new File(name); 32 | mName = f.getName(); 33 | mPath = f.getParent() == null ? null : f.getParent(); // need debug for first-level names 34 | mEntry = entry; 35 | if (mEntry.isDirectory()) 36 | mEntries = new ArrayList(); 37 | } 38 | 39 | public String getName() { return mName; } 40 | public ZipEntry getEntry() { return mEntry; } 41 | public InputStream getInputStream() throws IOException { return ZipFileExt.this.mZip.getInputStream(mEntry); } 42 | /* */ 43 | public List list() { 44 | return mEntries; 45 | } 46 | /* */ 47 | 48 | } 49 | 50 | private List mRoot = new ArrayList(); 51 | private Map mPathMap = new HashMap(); 52 | private ZipFile mZip = null; 53 | private ZipFileExt mParent = null; 54 | 55 | /** 56 | * 57 | * @param fileName 58 | * @throws IOException 59 | */ 60 | 61 | public ZipFileExt(String fileName) throws IOException { 62 | /** all files comes with full names /like/a/this/path **/ 63 | /** so, recreate virtual directory tree */ 64 | mZip = new ZipFile(fileName); 65 | 66 | List stack = new ArrayList(); /* */ 67 | List dirEntries = new ArrayList(); 68 | 69 | String dirName = null; 70 | Entry dirEntry = null; 71 | /* */ 72 | Enumeration entries = mZip.entries(); 73 | /* contract: 74 | * entry.isDirectory() == true && entry.getName().endsWith("/") == false 75 | * entry.getPath().endsWith("/") == false 76 | * */ 77 | 78 | while(entries.hasMoreElements()) { 79 | ZipEntry current = entries.nextElement(); 80 | String name = current.getName(); 81 | Entry e = new Entry(name,current); 82 | mPathMap.put(name,e); 83 | } 84 | 85 | /*** */ 86 | 87 | /** */ 88 | 89 | for(Entry entry : mPathMap.values()) { 90 | if (entry.mPath==null) 91 | mRoot.add(entry); 92 | else if (mPathMap.containsKey(entry.mPath)) { 93 | Entry parent = mPathMap.get(entry.mPath); 94 | parent.mEntries.add(entry); // connect entry to parent 95 | } else { 96 | /** */ 97 | throw new RuntimeException(); 98 | } 99 | } 100 | 101 | /** */ 102 | 103 | } 104 | 105 | /** 106 | * 107 | * @return Entry 108 | */ 109 | 110 | public List list() { 111 | return mRoot; 112 | } 113 | 114 | /* ZipFileExt */ 115 | public static void test_zip(String fileName) { 116 | try { 117 | ZipFileExt zfe = new ZipFileExt(fileName); 118 | } catch (IOException e) { 119 | e.printStackTrace(); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/MultiColumnTextViewExActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Typeface; 8 | import android.graphics.drawable.BitmapDrawable; 9 | import android.graphics.drawable.Drawable; 10 | import android.os.Build; 11 | import android.os.Bundle; 12 | import androidx.appcompat.app.ActionBarActivity; 13 | import android.text.Html; 14 | import android.view.Menu; 15 | import android.view.MenuItem; 16 | 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | 20 | import su.whs.hyphens.HyphenLineBreaker; 21 | import su.whs.watl.text.HtmlTagHandler; 22 | import su.whs.watl.ui.MultiColumnTextViewEx; 23 | 24 | 25 | public class MultiColumnTextViewExActivity extends ActionBarActivity { 26 | private TextOptionsHandler opts; 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_multi_column_text_view_ex); 31 | MultiColumnTextViewEx tv = (MultiColumnTextViewEx) findViewById(R.id.textView); 32 | Typeface font = Typeface.createFromAsset(tv.getContext().getAssets(), "fonts/GamjaFlower-Regular.ttf"); 33 | tv.setTypeface(font); 34 | opts = new TextOptionsHandler(this,tv); 35 | CharSequence text = Html.fromHtml(SampleContent.get(), new Html.ImageGetter() { 36 | /** 37 | * load images from assets/ folder 38 | * @param source - usually value for 'src' attribute of tag 39 | * @return Drawable object 40 | */ 41 | @Override 42 | public Drawable getDrawable(String source) { 43 | Context ctx = getApplicationContext(); 44 | AssetManager assetManager = ctx.getAssets(); 45 | 46 | InputStream is = null; 47 | try { 48 | is = assetManager.open(source); 49 | } catch (IOException e) { 50 | return null; 51 | } 52 | Bitmap bitmap = BitmapFactory.decodeStream(is); 53 | Drawable result = new BitmapDrawable(getResources(), bitmap); 54 | result.setBounds(0, 0, result.getIntrinsicWidth(), 55 | result.getIntrinsicHeight()); 56 | return result; 57 | } 58 | }, new HtmlTagHandler()); 59 | // tv.setColumnLimits(300, 600); // overrides attributes in xml 60 | tv.setText(text); 61 | tv.setTextIsSelectable(true); 62 | if (Build.VERSION.SDK_INT>10) 63 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 64 | tv.getOptions().setLineBreaker(HyphenLineBreaker.getInstance(this,"en_us")).setFilterEmptyLines(true); 65 | } 66 | 67 | @Override 68 | public boolean onCreateOptionsMenu(Menu menu) { 69 | // Inflate the menu; this adds items to the action bar if it is present. 70 | getMenuInflater().inflate(R.menu.text_options, menu); 71 | opts.restoreState(menu); 72 | return true; 73 | } 74 | 75 | @Override 76 | public boolean onOptionsItemSelected(MenuItem item) { 77 | // Handle action bar item clicks here. The action bar will 78 | // automatically handle clicks on the Home/Up button, so long 79 | // as you specify a parent activity in AndroidManifest.xml. 80 | if (opts.onOptionsItemSelected(item)) 81 | return true; 82 | int id = item.getItemId(); 83 | 84 | //noinspection SimplifiableIfStatement 85 | if (id == R.id.action_settings) { 86 | return true; 87 | } 88 | 89 | return super.onOptionsItemSelected(item); 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/TextOptionsHandler.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.Menu; 6 | import android.view.MenuItem; 7 | import android.widget.Button; 8 | 9 | import su.whs.watl.text.ContentView; 10 | import su.whs.watl.ui.ITextView; 11 | 12 | /** 13 | * Created by igor n. boulliev on 17.06.15. 14 | */ 15 | public class TextOptionsHandler { 16 | private ITextView textView; 17 | private Context ctx; 18 | 19 | public TextOptionsHandler(Context context, ITextView tv) { 20 | ctx = context; 21 | textView = tv; 22 | } 23 | 24 | public boolean onOptionsItemSelected(MenuItem item) { 25 | ContentView.Options opts = textView.getOptions(); 26 | int id = item.getItemId(); 27 | if (id == R.id.bigfont) { 28 | setFontSize(android.R.style.TextAppearance_Large,item); 29 | } else if (id == R.id.medfont) { 30 | setFontSize(android.R.style.TextAppearance_Medium,item); 31 | } else if (id == R.id.smallfont) { 32 | setFontSize(android.R.style.TextAppearance_Small,item); 33 | } else if (id == R.id.filter_empty) { 34 | if (item.isChecked()) { 35 | item.setChecked(false); 36 | opts.setFilterEmptyLines(false) 37 | .apply(); 38 | } else { 39 | item.setChecked(true); 40 | opts.setFilterEmptyLines(true) 41 | .apply(); 42 | } 43 | } else if (id == R.id.additionals_paragraphs_margins) { 44 | if (item.isChecked()) { 45 | item.setChecked(false); 46 | opts 47 | .setNewLineTopMargin(0) 48 | .setNewLineLeftMargin(0) 49 | .apply(); 50 | } else { 51 | item.setChecked(true); 52 | opts 53 | .setNewLineTopMargin(5) 54 | .setNewLineLeftMargin(15) 55 | .apply(); 56 | } 57 | } else { 58 | return false; 59 | } 60 | return true; 61 | } 62 | 63 | MenuItem mi_textBig; 64 | MenuItem mi_textMed; 65 | MenuItem mi_textSmall; 66 | 67 | public void restoreState(Menu menu) { 68 | MenuItem item; 69 | ContentView.Options opts = textView.getOptions(); 70 | item = menu.findItem(R.id.filter_empty); 71 | if (item!=null) { 72 | item.setChecked(opts.isFilterEmptyLines()); 73 | } 74 | item = menu.findItem(R.id.additionals_paragraphs_margins); 75 | if (item!=null) { 76 | item.setChecked(opts.getNewLineLeftMargin()>0); 77 | } 78 | 79 | mi_textBig = menu.findItem(R.id.bigfont); 80 | mi_textSmall = menu.findItem(R.id.smallfont); 81 | mi_textMed = menu.findItem(R.id.medfont); 82 | } 83 | 84 | private void setFontSize(int appearance, MenuItem item) { 85 | Button b =new Button(ctx); 86 | b.setTextAppearance(ctx,appearance); 87 | float size = b.getTextSize(); 88 | ContentView.Options opts = textView.getOptions(); 89 | opts 90 | .setTextSize(size) 91 | .apply(); 92 | uncheckAll(); 93 | item.setChecked(true); 94 | } 95 | 96 | private void uncheckAll() { 97 | if (mi_textBig==null||mi_textMed==null||mi_textSmall==null) { 98 | Log.e("TextOptionsHandler", "missing call restoreState(menu) - check onCreateOptionsMenu()"); 99 | return; 100 | } 101 | mi_textBig.setChecked(false); 102 | mi_textMed.setChecked(false); 103 | mi_textSmall.setChecked(false); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/assets/articles/gif_animation.html: -------------------------------------------------------------------------------- 1 | 2 | <> 3 |

Animation!

4 | 5 | 6 |
7 | 8 |

Chapter One

9 |
A Stop on the Salt Route
10 |
1000 B.C.
11 |

As they rounded a bend in the path that ran beside the river, Lara recognized the silhouette of a fig tree atop a nearby hill. The weather was hot and the days were long. The fig tree was in full leaf, but not yet bearing fruit. 12 | Soon Lara spotted other landmarks—an outcropping of limestone beside the path that had a silhouette like a man’s face, a marshy spot beside the river where the waterfowl were easily startled, a tall tree that looked like a man with his arms upraised. They were drawing near to the place where there was an island in the river. The island was a good spot to make camp. They would sleep on the island tonight. 13 | Lara had been back and forth along the river path many times in her short life.

14 |

Her people had not created the path—it had always been there, like the river—but their deerskin-shod feet and the wooden wheels of their handcarts kept the path well worn. Lara’s people were salt traders, and their livelihood took them on a continual journey. 15 | At the mouth of the river, the little group of half a dozen intermingled families gathered salt from the great salt beds beside the sea. They groomed and sifted the salt and loaded it into handcarts. When the carts were full, most of the group would stay behind, taking shelter amid rocks and simple lean-tos, while a band of fifteen or so of the heartier members set out on the path that ran alongside the river. 16 | With their precious cargo of salt, the travelers crossed the coastal lowlands and traveled toward the mountains. But Lara’s people never reached the mountaintops; they traveled only as far as the foothills. Many people lived in the forests and grassy meadows of the foothills, gathered in small villages. In return for salt, these people would give Lara’s people dried meat, animal skins, cloth spun from wool, clay pots, needles and scraping tools carved from bone, and little toys made of wood. 17 | Their bartering done, Lara and her people would travel back down the river path to the sea. The cycle would begin again. 18 | It had always been like this. Lara knew no other life.

She traveled back and forth, up and down the river path. No single place was home. She liked the seaside, where there was always fish to eat, and the gentle lapping of the waves lulled her to sleep at night. She was less fond of the foothills, where the path grew steep, the nights could be cold, and views of great distances made her dizzy. She felt uneasy in the villages, and was often shy around strangers. The path itself was where she felt most at home. She loved the smell of the river on a hot day, and the croaking of frogs at night. Vines grew amid the lush foliage along the river, with berries that were good to eat. Even on the hottest day, sundown brought a cool breeze off the water, which sighed and sang amid the reeds and tall grasses. 19 | Of all the places along the path, the area they were approaching, with the island in the river, was Lara’s favorite. 20 | The terrain along this stretch of the river was mostly flat, but in the immediate vicinity of the island, the land on the sunrise side was like a rumpled cloth, with hills and ridges and valleys. Among Lara’s people, there was a wooden baby’s crib, suitable for strapping to a cart, that had been passed down for generations. The island was shaped like that crib, longer than it was wide and pointed at the upriver end, where the flow had eroded both banks. The island was like a crib, and the group of hills on the sunrise side of the river were like old women mantled in heavy cloaks gathered to have a look at the baby in the crib—that was how Lara’s father had once described the lay of the land.

p> 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/HyphenTextViewExActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.graphics.Typeface; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import androidx.appcompat.app.ActionBarActivity; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | import su.whs.hyphens.HyphenLineBreaker; 11 | import su.whs.watl.text.ContentView; 12 | import su.whs.watl.ui.TextViewEx; 13 | 14 | 15 | public class HyphenTextViewExActivity extends ActionBarActivity implements ArticleView { 16 | private static final String[] articles = new String[] { 17 | ContentLoader.ARTICLE_SCIENCE1, 18 | ContentLoader.ARTICLE_SCIENCE2, 19 | ContentLoader.ARTICLE_OPENGLES, 20 | ContentLoader.ARTICLE_WORLD_OF_SHEAKSPEARE, 21 | }; 22 | private int currentArticle = 0; 23 | private TextOptionsHandler opts; 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_hyphen_text_view_ex); 28 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 29 | Typeface font = Typeface.createFromAsset(tv.getContext().getAssets(), "fonts/GamjaFlower-Regular.ttf"); 30 | tv.setTypeface(font); 31 | tv.setTextIsSelectable(true); 32 | if (Build.VERSION.SDK_INT>10) 33 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 34 | 35 | ContentView.Options opt = tv.getOptions(); 36 | // tv.getOptions() 37 | opt.setLineBreaker(HyphenLineBreaker.getInstance(this,"en_us")) 38 | .setFilterEmptyLines(true); 39 | // .setNewLineLeftMargin(20) 40 | // .setNewLineTopMargin(8); 41 | ((wATLApp)getApplication()).getArticle(articles[currentArticle],this); 42 | opts = new TextOptionsHandler(this,tv); 43 | 44 | } 45 | 46 | @Override 47 | public boolean onCreateOptionsMenu(Menu menu) { 48 | // Inflate the menu; this adds items to the action bar if it is present. 49 | getMenuInflater().inflate(R.menu.menu_text_view_ex_scroll, menu); 50 | opts.restoreState(menu); 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean onOptionsItemSelected(MenuItem item) { 56 | // Handle action bar item clicks here. The action bar will 57 | // automatically handle clicks on the Home/Up button, so long 58 | // as you specify a parent activity in AndroidManifest.xml. 59 | int id = item.getItemId(); 60 | if (opts.onOptionsItemSelected(item)) 61 | return true; 62 | //noinspection SimplifiableIfStatement 63 | if (id == R.id.action_settings) { 64 | return true; 65 | } else if (id == R.id.test_set_text) { 66 | if (currentArticle>3) currentArticle=0; 67 | ((wATLApp)getApplication()).getArticle(articles[currentArticle],this); 68 | currentArticle++; 69 | return true; 70 | } 71 | 72 | return super.onOptionsItemSelected(item); 73 | } 74 | 75 | @Override 76 | public void onSaveInstanceState(Bundle out) { 77 | super.onSaveInstanceState(out); 78 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 79 | out.putBundle("OPTIONS", tv.getOptions().getState()); 80 | } 81 | 82 | @Override 83 | public void onRestoreInstanceState(Bundle in) { 84 | super.onRestoreInstanceState(in); 85 | if (in.containsKey("OPTIONS")) { 86 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 87 | tv.getOptions().set(in.getBundle("OPTIONS")); 88 | } 89 | } 90 | 91 | @Override 92 | public void setLoadingState(boolean state, int percents) { 93 | 94 | } 95 | 96 | @Override 97 | public void setContent(String title, String author, String source, CharSequence content) { 98 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 99 | tv.setText(content); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/RTLTestActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.ActionBarActivity; 6 | import android.text.SpannableStringBuilder; 7 | import android.text.Spanned; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | 11 | import java.text.Bidi; 12 | import java.util.ArrayList; 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | import su.whs.watl.ui.TextViewEx; 17 | 18 | 19 | public class RTLTestActivity extends ActionBarActivity implements ArticleView { 20 | private TextOptionsHandler opts; 21 | private static final String[] articles = new String[] { 22 | ContentLoader.RTL_TEST, 23 | ContentLoader.ARTICLE_SCIENCE2, 24 | ContentLoader.ARTICLE_OPENGLES, 25 | }; 26 | private int currentArticle = 0; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_text_view_ex_scroll); 32 | 33 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 34 | ((wATLApp)getApplication()).getArticle(ContentLoader.RTL_TEST,this); 35 | opts = new TextOptionsHandler(this,tv); 36 | } 37 | 38 | @Override 39 | public boolean onCreateOptionsMenu(Menu menu) { 40 | // Inflate the menu; this adds items to the action bar if it is present. 41 | getMenuInflater().inflate(R.menu.menu_text_view_ex_scroll, menu); 42 | opts.restoreState(menu); 43 | return true; 44 | } 45 | 46 | @Override 47 | public boolean onOptionsItemSelected(MenuItem item) { 48 | // Handle action bar item clicks here. The action bar will 49 | // automatically handle clicks on the Home/Up button, so long 50 | // as you specify a parent activity in AndroidManifest.xml. 51 | int id = item.getItemId(); 52 | if (opts.onOptionsItemSelected(item)) 53 | return true; 54 | //noinspection SimplifiableIfStatement 55 | // if (id == R.id.test_set_text) { 56 | // if (currentArticle>2) currentArticle=0; 57 | // ((wATLApp)getApplication()).getArticle(articles[currentArticle],this); 58 | // // currentArticle++; 59 | // return true; 60 | // } 61 | 62 | return super.onOptionsItemSelected(item); 63 | } 64 | 65 | @Override 66 | public void onSaveInstanceState(Bundle out) { 67 | super.onSaveInstanceState(out); 68 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 69 | out.putBundle("OPTIONS",tv.getOptions().getState()); 70 | } 71 | 72 | @Override 73 | public void onRestoreInstanceState(Bundle in) { 74 | super.onRestoreInstanceState(in); 75 | if (in.containsKey("OPTIONS")) { 76 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 77 | tv.getOptions().set(in.getBundle("OPTIONS")); 78 | } 79 | } 80 | 81 | @Override 82 | public void setLoadingState(boolean state, int percents) { 83 | 84 | } 85 | 86 | @Override 87 | public void setContent(String title, String author, String source, CharSequence content) { 88 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 89 | tv.setText(workaround(content)); // 90 | tv.setTextIsSelectable(true); 91 | if (Build.VERSION.SDK_INT>10) 92 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 93 | } 94 | 95 | public Spanned workaround(CharSequence string) { 96 | SpannableStringBuilder ssb = new SpannableStringBuilder(string); 97 | Bidi bidi = new Bidi(string.toString(), Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT); 98 | List inserts = new ArrayList(); 99 | if (bidi.isMixed()) { 100 | for (int run = 0; run < bidi.getRunCount(); run++) { 101 | int end = bidi.getRunLimit(run); 102 | inserts.add(end); 103 | } 104 | Collections.reverse(inserts); 105 | for (int pos : inserts) ssb.insert(pos,"\n"); 106 | } 107 | return ssb; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/AssetGifDrawable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 whs.su 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package su.whs.watl.samples; 16 | 17 | import android.content.Context; 18 | import android.graphics.Bitmap; 19 | import android.graphics.Canvas; 20 | import android.graphics.drawable.BitmapDrawable; 21 | import android.graphics.drawable.Drawable; 22 | import android.os.Build; 23 | 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | 27 | import pl.droidsonroids.gif.GifDrawable; 28 | import su.whs.watl.samples.utils.GifDecoder; 29 | import su.whs.wlazydrawable.PreviewDrawable; 30 | 31 | /** 32 | * Created by igor n. boulliev on 31.08.15. 33 | */ 34 | 35 | /** 36 | * demo code for show animated drawables in TextViewEx 37 | * 38 | * LazyDrawable required for animation on demand launch, 39 | * and for support AOSP < 11 40 | * 41 | * 42 | */ 43 | 44 | 45 | public class AssetGifDrawable extends PreviewDrawable { 46 | private String mPath; 47 | private Context mContext; 48 | private boolean mFullVersionLoaded = false; 49 | 50 | public AssetGifDrawable(Context context, String path) { 51 | super(context,800, 500); 52 | setScaleType(ScaleType.FILL); 53 | mPath = path; 54 | mContext = context; 55 | } 56 | 57 | @Override 58 | public void onVisibilityChanged(boolean b) { 59 | 60 | } 61 | 62 | @Override 63 | protected void onLoadingError() { 64 | 65 | } 66 | 67 | /* call loadFullImage and launch animation */ 68 | @Override 69 | public void start() { 70 | if (!mFullVersionLoaded) { 71 | super.loadFullDrawable(); 72 | } 73 | super.start(); 74 | } 75 | 76 | @Override 77 | protected Drawable getPreviewDrawable() { 78 | GifDecoder decoder = new GifDecoder(); 79 | try { 80 | InputStream inputStream = mContext.getAssets().open(mPath); 81 | decoder.read(inputStream, 0); 82 | decoder.advance(); 83 | Bitmap frame = decoder.getNextFrame(); 84 | Drawable result = new BitmapDrawable(mContext.getResources(),frame); 85 | inputStream.close(); 86 | return result; 87 | } catch (IOException e) { 88 | onLoadingError(); 89 | return null; 90 | } 91 | } 92 | 93 | @Override 94 | protected Drawable getFullDrawable() { 95 | try { // sleep added to display loading animation 96 | Thread.sleep(1000); 97 | } catch (InterruptedException e) { 98 | // e.printStackTrace(); 99 | } 100 | if (mFullVersionLoaded) return null; 101 | try { 102 | /* GifDrawable implements Animatable, so we can show animations */ 103 | Drawable r = Build.VERSION.SDK_INT > 18 ? new GifDrawable(mContext.getAssets().open(mPath)) : new GifDrawableCompat(mContext.getAssets().open(mPath)); 104 | mFullVersionLoaded = true; 105 | return r; 106 | } catch (IOException e) { 107 | onLoadingError(); 108 | return null; 109 | } 110 | } 111 | 112 | @Override 113 | protected int getSampling() { 114 | return 1; 115 | } 116 | 117 | public String getPath() { 118 | return mPath; 119 | } 120 | private Drawable mPlayButtonDrawable; 121 | public void setPlayButtonDrawable(Drawable rr) { 122 | rr.setBounds(0,0,rr.getIntrinsicWidth(),rr.getIntrinsicHeight()); 123 | mPlayButtonDrawable = rr; 124 | invalidateSelfOnUiThread(); 125 | } 126 | 127 | @Override 128 | public void draw(Canvas canvas) { 129 | super.draw(canvas); 130 | 131 | if (!isLoading() && !isRunning() && mPlayButtonDrawable!=null) { 132 | super.drawProgress(canvas,mPlayButtonDrawable,0,255); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/TextViewExScrollActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.graphics.Typeface; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import androidx.appcompat.app.ActionBarActivity; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | import su.whs.watl.ui.TextViewEx; 11 | 12 | 13 | public class TextViewExScrollActivity extends ActionBarActivity implements ArticleView { 14 | /** helper for option menu bindings to TextViewEx options **/ 15 | private TextOptionsHandler opts; 16 | /** articles variants **/ 17 | private static final String[] articles = new String[] { 18 | ContentLoader.ARTICLE_SCIENCE1, 19 | ContentLoader.ARTICLE_SCIENCE2, 20 | ContentLoader.ARTICLE_OPENGLES, 21 | }; 22 | private int currentArticle = 0; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | /** activity layout **/ 28 | setContentView(R.layout.activity_text_view_ex_scroll); 29 | /** find TextViewEx **/ 30 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 31 | Typeface font = Typeface.createFromAsset(tv.getContext().getAssets(), "fonts/GamjaFlower-Regular.ttf"); 32 | tv.setTypeface(font); 33 | /** 34 | * use article loader to assign content to TextViewEx 35 | * see setContent() method for this activity 36 | * **/ 37 | ((wATLApp)getApplication()).getArticle(articles[currentArticle],this); 38 | currentArticle++; 39 | /** initialize option menu bindings **/ 40 | opts = new TextOptionsHandler(this,tv); 41 | /** turn on empty lines elimination **/ 42 | tv.getOptions().setFilterEmptyLines(true); 43 | } 44 | 45 | @Override 46 | public boolean onCreateOptionsMenu(Menu menu) { 47 | // Inflate the menu; this adds items to the action bar if it is present. 48 | getMenuInflater().inflate(R.menu.menu_text_view_ex_scroll, menu); 49 | opts.restoreState(menu); 50 | return true; 51 | } 52 | 53 | @Override 54 | public boolean onOptionsItemSelected(MenuItem item) { 55 | // Handle action bar item clicks here. The action bar will 56 | // automatically handle clicks on the Home/Up button, so long 57 | // as you specify a parent activity in AndroidManifest.xml. 58 | int id = item.getItemId(); 59 | if (opts.onOptionsItemSelected(item)) 60 | return true; 61 | //noinspection SimplifiableIfStatement 62 | if (id == R.id.test_set_text) { 63 | if (currentArticle>2) currentArticle=0; 64 | ((wATLApp)getApplication()).getArticle(articles[currentArticle],this); 65 | currentArticle++; 66 | return true; 67 | } 68 | 69 | return super.onOptionsItemSelected(item); 70 | } 71 | 72 | @Override 73 | public void onSaveInstanceState(Bundle out) { 74 | super.onSaveInstanceState(out); 75 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 76 | out.putBundle("OPTIONS",tv.getOptions().getState()); 77 | } 78 | 79 | @Override 80 | public void onRestoreInstanceState(Bundle in) { 81 | super.onRestoreInstanceState(in); 82 | if (in.containsKey("OPTIONS")) { 83 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 84 | tv.getOptions().set(in.getBundle("OPTIONS")); 85 | } 86 | } 87 | 88 | @Override 89 | public void setLoadingState(boolean state, int percents) { 90 | 91 | } 92 | 93 | /** 94 | * called when Article content ready 95 | * @param title - title of article 96 | * @param author - author 97 | * @param source - source url 98 | * @param content - content 99 | */ 100 | 101 | @Override 102 | public void setContent(String title, String author, String source, CharSequence content) { 103 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 104 | /** setText() with given content **/ 105 | tv.setText(content); 106 | /** enable selection **/ 107 | tv.setTextIsSelectable(true); 108 | if (Build.VERSION.SDK_INT>10) // if android version > 3.0 - turn on action mode 109 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 27 | 28 | 32 | 35 | 36 | 40 | 43 | 44 | 48 | 51 | 52 | 56 | 59 | 60 | 64 | 67 | 68 | 72 | 75 | 76 | 80 | 83 | 84 | 88 | 91 | 92 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/AnimationActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | /** 4 | * Created by igor n. boulliev on 31.08.15. 5 | */ 6 | 7 | 8 | import android.graphics.Rect; 9 | import android.graphics.RectF; 10 | import android.graphics.drawable.Animatable; 11 | import android.graphics.drawable.Drawable; 12 | import android.os.Build; 13 | import android.os.Bundle; 14 | import androidx.appcompat.app.ActionBarActivity; 15 | import android.text.style.DynamicDrawableSpan; 16 | import android.view.Menu; 17 | import android.view.MenuItem; 18 | import android.view.View; 19 | 20 | import su.whs.watl.text.DynamicDrawableInteractionListener; 21 | import su.whs.watl.text.ImagePlacementHandler; 22 | import su.whs.watl.ui.TextViewEx; 23 | 24 | 25 | public class AnimationActivity extends ActionBarActivity implements ArticleView { 26 | private TextOptionsHandler opts; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_text_view_ex_scroll); 32 | 33 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 34 | ((wATLApp)getApplication()).getArticle("gif_animation",this); 35 | opts = new TextOptionsHandler(this,tv); 36 | tv.getOptions() 37 | .setDrawableMinimumScaleFactor(1.0f) 38 | .setDrawablePaddings(10,10,10,10) 39 | .setDrawableWrapRatioTreshold(.2f) 40 | .setImagePlacementHandler(new ImagePlacementHandler.DefaultImagePlacementHandler()); 41 | tv.setDynamicDrawableInteractionListener(new DynamicDrawableInteractionListener() { 42 | @Override 43 | public void onClicked(DynamicDrawableSpan span, Rect bounds, View view) { 44 | Drawable drawable = span.getDrawable(); 45 | if (drawable instanceof Animatable) { 46 | if (!((Animatable)drawable).isRunning()) 47 | ((Animatable)drawable).start(); 48 | else 49 | ((Animatable)drawable).stop(); 50 | } 51 | } 52 | 53 | @Override 54 | public void onLongClick(DynamicDrawableSpan span, RectF bounds, View view) { 55 | 56 | } 57 | }); 58 | } 59 | 60 | @Override 61 | public boolean onCreateOptionsMenu(Menu menu) { 62 | // Inflate the menu; this adds items to the action bar if it is present. 63 | getMenuInflater().inflate(R.menu.menu_text_view_ex_scroll, menu); 64 | opts.restoreState(menu); 65 | return true; 66 | } 67 | 68 | @Override 69 | public boolean onOptionsItemSelected(MenuItem item) { 70 | // Handle action bar item clicks here. The action bar will 71 | // automatically handle clicks on the Home/Up button, so long 72 | // as you specify a parent activity in AndroidManifest.xml. 73 | int id = item.getItemId(); 74 | if (opts.onOptionsItemSelected(item)) 75 | return true; 76 | //noinspection SimplifiableIfStatement 77 | if (id == R.id.test_set_text) { 78 | ((wATLApp)getApplication()).getArticle("gif_animation",this); 79 | return true; 80 | } 81 | 82 | return super.onOptionsItemSelected(item); 83 | } 84 | 85 | @Override 86 | public void onSaveInstanceState(Bundle out) { 87 | super.onSaveInstanceState(out); 88 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 89 | out.putBundle("OPTIONS",tv.getOptions().getState()); 90 | } 91 | 92 | @Override 93 | public void onRestoreInstanceState(Bundle in) { 94 | super.onRestoreInstanceState(in); 95 | if (in.containsKey("OPTIONS")) { 96 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 97 | tv.getOptions().set(in.getBundle("OPTIONS")); 98 | } 99 | } 100 | 101 | @Override 102 | public void setLoadingState(boolean state, int percents) { 103 | 104 | } 105 | 106 | @Override 107 | public void setContent(String title, String author, String source, CharSequence content) { 108 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 109 | tv.setText(content); 110 | tv.setTextIsSelectable(true); 111 | if (Build.VERSION.SDK_INT>10) 112 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/utils/ArticleSerializer.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.drawable.Drawable; 6 | import android.text.Spanned; 7 | import android.text.style.DynamicDrawableSpan; 8 | import android.text.style.ImageSpan; 9 | import android.util.Log; 10 | 11 | import java.io.DataInputStream; 12 | import java.io.DataOutputStream; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | 16 | import su.whs.watl.experimental.SpannedSerializator; 17 | import su.whs.watl.samples.AssetGifDrawable; 18 | import su.whs.watl.samples.TaggedBitmapDrawable; 19 | 20 | /** 21 | * Created by igor n. boulliev on 02.09.15. 22 | */ 23 | public class ArticleSerializer extends SpannedSerializator { 24 | 25 | private Context mContext; 26 | 27 | public ArticleSerializer(Context context, Spanned string) { 28 | super(string); 29 | mContext = context; 30 | } 31 | 32 | public ArticleSerializer(Context context) { 33 | super(); 34 | mContext = context; 35 | } 36 | 37 | public static Spanned read(Context context,DataInputStream dis) throws IOException, InvalidVersionException, ReadError { 38 | SpannedSerializator ss = new ArticleSerializer(context); 39 | return ss.deserialize(dis); 40 | } 41 | 42 | /** 43 | @Override 44 | public void write(Object span, DataOutputStream dos) { 45 | 46 | } 47 | 48 | @Override 49 | public Object read(int tag, DataInputStream dis) { 50 | 51 | } */ 52 | 53 | @Override 54 | public void writeDynamicDrawableSpan(DynamicDrawableSpan span, DataOutputStream dos) { 55 | Drawable drawable = span.getDrawable(); 56 | if (drawable instanceof TaggedBitmapDrawable) { 57 | String tag = ((TaggedBitmapDrawable)drawable).getTag(); 58 | try { 59 | dos.writeInt(21); 60 | dos.writeUTF(tag); 61 | } catch (IOException e) { 62 | // 63 | } 64 | } else if (drawable instanceof AssetGifDrawable) { 65 | String tag = ((AssetGifDrawable)drawable).getPath(); 66 | try { 67 | dos.writeInt(22); 68 | dos.writeUTF(tag); 69 | } catch (IOException e) { 70 | 71 | } 72 | } else { 73 | try { 74 | dos.writeInt(23); 75 | super.writeDynamicDrawableSpan(span,dos); 76 | } catch (IOException e) { 77 | e.printStackTrace(); 78 | } 79 | // throw new IllegalArgumentException("could not serialize drawable class: " + drawable.getClass()); 80 | } 81 | try { 82 | dos.writeInt(0xaaaa); // sync mark 83 | } catch (IOException e) { 84 | 85 | } 86 | } 87 | 88 | @Override 89 | public DynamicDrawableSpan readDynamicDrawableSpan(DataInputStream dis) throws ReadError { 90 | DynamicDrawableSpan result; 91 | int type = -1; 92 | try { 93 | type = dis.readInt(); 94 | if (type == 21) { 95 | String tag = dis.readUTF(); 96 | InputStream is = mContext.getAssets().open(tag); 97 | result = new ImageSpan(mContext, BitmapFactory.decodeStream(is)); 98 | } else if (type == 22) { 99 | String tag = dis.readUTF(); 100 | AssetGifDrawable dr = new AssetGifDrawable(mContext, tag); 101 | Drawable rr = mContext.getResources().getDrawable( 102 | su.whs.watl.R.mipmap.ic_play_circle_btn 103 | ); 104 | dr.setPlayButtonDrawable(rr); 105 | result = new ImageSpan(dr, tag); 106 | } else if (type == 23) { 107 | result = super.readDynamicDrawableSpan(dis); 108 | } else { 109 | result = null; 110 | throw new ReadError("unknown type while readDynamicDrawableSpan:" + type); 111 | } 112 | } catch (IOException e) { 113 | e.printStackTrace(); 114 | result = null; 115 | } 116 | int syncMark = 0; 117 | try { 118 | syncMark = dis.readInt(); 119 | } catch (IOException e) { 120 | Log.e("AS", "error reading sync mark"); 121 | } 122 | if (syncMark!=0xaaaa) { 123 | throw new ReadError("lost sync after read drawable with tag:"+type); 124 | } 125 | return result; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/ReaderViewPagerTransformer.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | 4 | import android.annotation.TargetApi; 5 | import android.os.Build; 6 | import androidx.core.view.ViewPager; 7 | import android.util.Log; 8 | import android.view.View; 9 | /* 10 | * ViewPager transformation animation invoked when a visible/attached page is scrolled - before 11 | * changing this, first see https://code.google.com/p/android/issues/detail?id=58918#c5 12 | * tl;dr make sure to remove X translation when a page is no longer fully visible 13 | * 14 | * Usage: viewPager.setPageTransformer(false, new ReaderViewPagerTransformer(TransformType.FLOW)); 15 | */ 16 | public class ReaderViewPagerTransformer implements ViewPager.PageTransformer { 17 | private static final String TAG = "RVPT"; 18 | 19 | public enum TransformType { 20 | FLOW, 21 | DEPTH, 22 | ZOOM, 23 | SLIDE_OVER 24 | } 25 | private final TransformType mTransformType; 26 | 27 | ReaderViewPagerTransformer(TransformType transformType) { 28 | mTransformType = transformType; 29 | } 30 | 31 | private static final float MIN_SCALE_DEPTH = 0.75f; 32 | private static final float MIN_SCALE_ZOOM = 0.85f; 33 | private static final float MIN_ALPHA_ZOOM = 0.5f; 34 | private static final float SCALE_FACTOR_SLIDE = 0.85f; 35 | private static final float MIN_ALPHA_SLIDE = 0.35f; 36 | 37 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 38 | public void transformPage(View page, float position) { 39 | final float alpha; 40 | final float scale; 41 | final float translationX; 42 | 43 | switch (mTransformType) { 44 | case FLOW: 45 | if (position>-0.9f && position<0.9f) { 46 | page.setRotationY(position * -30f); 47 | Log.v(TAG, "FLOW:" + position); 48 | } else 49 | page.setRotation(0f); 50 | page.destroyDrawingCache(); 51 | return; 52 | 53 | case SLIDE_OVER: 54 | if (position < 0 && position > -1) { 55 | // this is the page to the left 56 | scale = Math.abs(Math.abs(position) - 1) * (1.0f - SCALE_FACTOR_SLIDE) + SCALE_FACTOR_SLIDE; 57 | alpha = Math.max(MIN_ALPHA_SLIDE, 1 - Math.abs(position)); 58 | int pageWidth = page.getWidth(); 59 | float translateValue = position * -pageWidth; 60 | if (translateValue > -pageWidth) { 61 | translationX = translateValue; 62 | } else { 63 | translationX = 0; 64 | } 65 | } else { 66 | alpha = 1; 67 | scale = 1; 68 | translationX = 0; 69 | } 70 | break; 71 | 72 | case DEPTH: 73 | if (position > 0 && position < 1) { 74 | // moving to the right 75 | alpha = (1 - position); 76 | scale = MIN_SCALE_DEPTH + (1 - MIN_SCALE_DEPTH) * (1 - Math.abs(position)); 77 | translationX = (page.getWidth() * -position); 78 | } else { 79 | // use default for all other cases 80 | alpha = 1; 81 | scale = 1; 82 | translationX = 0; 83 | } 84 | break; 85 | 86 | case ZOOM: 87 | if (position >= -1 && position <= 1) { 88 | scale = Math.max(MIN_SCALE_ZOOM, 1 - Math.abs(position)); 89 | alpha = MIN_ALPHA_ZOOM + 90 | (scale - MIN_SCALE_ZOOM) / (1 - MIN_SCALE_ZOOM) * (1 - MIN_ALPHA_ZOOM); 91 | float vMargin = page.getHeight() * (1 - scale) / 2; 92 | float hMargin = page.getWidth() * (1 - scale) / 2; 93 | if (position < 0) { 94 | translationX = (hMargin - vMargin / 2); 95 | } else { 96 | translationX = (-hMargin + vMargin / 2); 97 | } 98 | } else { 99 | alpha = 1; 100 | scale = 1; 101 | translationX = 0; 102 | } 103 | break; 104 | 105 | default: 106 | return; 107 | } 108 | 109 | page.setAlpha(alpha); 110 | page.setTranslationX(translationX); 111 | page.setScaleX(scale); 112 | page.setScaleY(scale); 113 | } 114 | 115 | } -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.drawable.BitmapDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import androidx.appcompat.app.ActionBarActivity; 12 | import android.text.Html; 13 | import android.text.SpannableStringBuilder; 14 | import android.view.Menu; 15 | import android.view.MenuItem; 16 | 17 | import java.io.BufferedReader; 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.io.InputStreamReader; 21 | import java.io.UnsupportedEncodingException; 22 | 23 | import su.whs.hyphens.HyphenLineBreaker; 24 | import su.whs.watl.text.HtmlTagHandler; 25 | import su.whs.watl.ui.TextViewEx; 26 | 27 | 28 | public class AboutActivity extends ActionBarActivity { 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_about); 34 | TextViewEx tv = (TextViewEx) findViewById(R.id.textView); 35 | 36 | Context ctx = getApplicationContext(); 37 | AssetManager assetManager = ctx.getAssets(); 38 | 39 | InputStream is = null; 40 | CharSequence text = "error reading about.html"; 41 | 42 | try { 43 | is = assetManager.open("about.html"); 44 | BufferedReader in = 45 | new BufferedReader(new InputStreamReader(is, "utf-8")); 46 | SpannableStringBuilder ssb = new SpannableStringBuilder(); 47 | String str; 48 | int emptyLinesCount = 0; 49 | while ((str = in.readLine()) != null) { 50 | if (str.length() < 1) 51 | emptyLinesCount++; 52 | if (emptyLinesCount > 1) 53 | ssb.append('\n'); 54 | 55 | if (str.length() > 0) { 56 | ssb.append(str); 57 | ssb.append(" "); 58 | emptyLinesCount = 0; 59 | } 60 | } 61 | 62 | text = Html.fromHtml(ssb.toString(), new Html.ImageGetter() { 63 | @Override 64 | public Drawable getDrawable(String source) { 65 | if ("logo.png".equals(source)) { 66 | Drawable result = getResources() 67 | .getDrawable(R.mipmap.ic_logo); 68 | result.setBounds(0, 0, result.getIntrinsicWidth(), 69 | result.getIntrinsicHeight()); 70 | return result; 71 | } 72 | Context ctx = getApplicationContext(); 73 | AssetManager assetManager = ctx.getAssets(); 74 | 75 | InputStream is = null; 76 | try { 77 | is = assetManager.open(source); 78 | } catch (IOException e) { 79 | return null; 80 | } 81 | Bitmap bitmap = BitmapFactory.decodeStream(is); 82 | Drawable result = new BitmapDrawable(getResources(), bitmap); 83 | result.setBounds(0, 0, result.getIntrinsicWidth(), 84 | result.getIntrinsicHeight()); 85 | return result; 86 | } 87 | }, new HtmlTagHandler()); 88 | } catch (UnsupportedEncodingException e) { 89 | e.printStackTrace(); 90 | } catch (IOException e) { 91 | e.printStackTrace(); 92 | } 93 | 94 | tv.setText(text); 95 | tv.setTextIsSelectable(true); 96 | if (Build.VERSION.SDK_INT>10) 97 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 98 | 99 | tv.getOptions() 100 | .setLineBreaker(HyphenLineBreaker.getInstance(this,"en_us")) 101 | .setNewLineLeftMargin(25) 102 | .setNewLineTopMargin(10); 103 | } 104 | 105 | @Override 106 | public boolean onCreateOptionsMenu(Menu menu) { 107 | // Inflate the menu; this adds items to the action bar if it is present. 108 | getMenuInflater().inflate(R.menu.menu_about, menu); 109 | return true; 110 | } 111 | 112 | @Override 113 | public boolean onOptionsItemSelected(MenuItem item) { 114 | // Handle action bar item clicks here. The action bar will 115 | // automatically handle clicks on the Home/Up button, so long 116 | // as you specify a parent activity in AndroidManifest.xml. 117 | int id = item.getItemId(); 118 | 119 | //noinspection SimplifiableIfStatement 120 | if (id == R.id.action_settings) { 121 | return true; 122 | } 123 | 124 | return super.onOptionsItemSelected(item); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /whsutils/src/main/java/su/whs/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package su.whs.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.os.StatFs; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.io.FileOutputStream; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.io.OutputStream; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * Created by igor n. boulliev on 01.05.15. 20 | */ 21 | public class FileUtils { 22 | 23 | public interface ContentFilter { 24 | void filter(byte[] buffer, int len); 25 | } 26 | 27 | public static void Copy(File src, File dst) throws IOException { 28 | for (File content : src.listFiles()) { 29 | if (content.isDirectory()) { 30 | File tgt = new File(dst,content.getName()); 31 | if (!tgt.exists()) tgt.mkdir(); 32 | Copy(content,tgt); 33 | } else { 34 | File tgt = new File(dst,content.getName()); 35 | InputStream in = new FileInputStream(content); 36 | OutputStream out = new FileOutputStream(tgt); 37 | byte[] buf = new byte[8192]; 38 | int len; 39 | while ((len = in.read(buf)) > 0) { 40 | out.write(buf, 0, len); 41 | } 42 | in.close(); 43 | out.close(); 44 | } 45 | } 46 | } 47 | 48 | public static void Copy(File src, File dst, ContentFilter filter) throws IOException { 49 | for (File content : src.listFiles()) { 50 | if (content.isDirectory()) { 51 | File tgt = new File(dst,content.getName()); 52 | if (!tgt.exists()) tgt.mkdir(); 53 | Copy(content,tgt, filter); 54 | } else { 55 | File tgt = new File(dst,content.getName()); 56 | InputStream in = new FileInputStream(content); 57 | OutputStream out = new FileOutputStream(tgt); 58 | byte[] buf = new byte[8192]; 59 | int len; 60 | while ((len = in.read(buf)) > 0) { 61 | if (filter!=null) 62 | filter.filter(buf,len); 63 | out.write(buf, 0, len); 64 | } 65 | in.close(); 66 | out.close(); 67 | } 68 | } 69 | } 70 | 71 | public static void Remove(File dir) { 72 | if (dir.isDirectory() && dir.exists()) 73 | for (File child : dir.listFiles()) 74 | Remove(child); 75 | dir.delete(); 76 | } 77 | 78 | public static String convertStreamToString(InputStream is) throws Exception { 79 | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 80 | StringBuilder sb = new StringBuilder(); 81 | String line = null; 82 | while ((line = reader.readLine()) != null) { 83 | sb.append(line).append("\n"); 84 | } 85 | reader.close(); 86 | return sb.toString(); 87 | } 88 | 89 | public static String getStringFromFile (String filePath) throws Exception { 90 | File fl = new File(filePath); 91 | FileInputStream fin = new FileInputStream(fl); 92 | String ret = convertStreamToString(fin); 93 | //Make sure you close all streams. 94 | fin.close(); 95 | return ret; 96 | } 97 | 98 | public static long freeSpace(String path) { 99 | StatFs stat = new StatFs(path); 100 | if (Build.VERSION.SDK_INTs2 ? s1 : s2; 114 | } 115 | 116 | public static String[] getWritableStorages(Context context) { 117 | StatFs stat = null; 118 | List result = new ArrayList(); 119 | File cache = context.getCacheDir(); 120 | File cacheExt = context.getExternalCacheDir(); 121 | long cacheSize = maxSpace(cache,cacheExt); 122 | File files = context.getFilesDir(); 123 | 124 | File filesExt = context.getExternalFilesDir(null); 125 | long filesSize = maxSpace(files,filesExt); 126 | 127 | File mnt = new File("/mnt"); 128 | if (mnt.exists() && mnt.isDirectory()) { 129 | File[] points = mnt.listFiles(); 130 | 131 | } 132 | 133 | if (result.size()<1) return null; 134 | 135 | String[] r = new String[result.size()]; 136 | for(int i=0; i tag 50 | * @return Drawable object 51 | */ 52 | @Override 53 | public Drawable getDrawable(String source) { 54 | Context ctx = getApplicationContext(); 55 | AssetManager assetManager = ctx.getAssets(); 56 | 57 | InputStream is = null; 58 | try { 59 | is = assetManager.open(source); 60 | } catch (IOException e) { 61 | return null; 62 | } 63 | Bitmap bitmap = BitmapFactory.decodeStream(is); 64 | Drawable result = new BitmapDrawable(getResources(), bitmap); 65 | result.setBounds(0, 0, result.getIntrinsicWidth(), 66 | result.getIntrinsicHeight()); 67 | return result; 68 | } 69 | }, new HtmlTagHandler()); 70 | 71 | tv.setText(text); 72 | tv.setTextIsSelectable(true); 73 | if (Build.VERSION.SDK_INT>10) 74 | tv.setCustomSelectionActionModeCallback(new SampleActionModeCallback(tv)); 75 | 76 | /** create HyphenLineBreaker with preloaded patterns and assign it to TextViewEx **/ 77 | tv.getOptions().setLineBreaker(HyphenLineBreaker.getInstance(this,"en_us")); 78 | /* screenshoting */ 79 | tv.getOptions() 80 | /** configure line spacing multiplier **/ 81 | .setLineSpacingMultiplier(0.5f) 82 | /** reduce line spacing by 4px **/ 83 | .setLineSpacingAdd(-4) 84 | /** set paragraph first line margin to left **/ 85 | .setNewLineLeftMargin(25) 86 | /** configure text paddings **/ 87 | .setTextPaddings(5,4,5,4); 88 | 89 | opts = new TextOptionsHandler(this,tv); 90 | } 91 | 92 | @Override 93 | public boolean onCreateOptionsMenu(Menu menu) { 94 | // Inflate the menu; this adds items to the action bar if it is present. 95 | // getMenuInflater().inflate(R.menu.menu_hyphen_text_view_ex, menu); 96 | getMenuInflater().inflate(R.menu.menu_text_view_ex_scroll, menu); 97 | opts.restoreState(menu); 98 | return true; 99 | } 100 | 101 | @Override 102 | public boolean onOptionsItemSelected(MenuItem item) { 103 | // Handle action bar item clicks here. The action bar will 104 | // automatically handle clicks on the Home/Up button, so long 105 | // as you specify a parent activity in AndroidManifest.xml. 106 | int id = item.getItemId(); 107 | if (opts.onOptionsItemSelected(item)) 108 | return true; 109 | //noinspection SimplifiableIfStatement 110 | if (id == R.id.action_settings) { 111 | return true; 112 | } else if (id == R.id.test_set_text) { 113 | tv.setText(text); 114 | return true; 115 | } 116 | 117 | return super.onOptionsItemSelected(item); 118 | } 119 | 120 | @Override 121 | public void onSaveInstanceState(Bundle out) { 122 | super.onSaveInstanceState(out); 123 | out.putBundle("OPTIONS", tv.getOptions().getState()); 124 | } 125 | 126 | @Override 127 | public void onRestoreInstanceState(Bundle in) { 128 | super.onRestoreInstanceState(in); 129 | if (in.containsKey("OPTIONS")) { 130 | tv.getOptions().set(in.getBundle("OPTIONS")); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/su/whs/watl/samples/wATLApp.java: -------------------------------------------------------------------------------- 1 | package su.whs.watl.samples; 2 | 3 | import android.app.Application; 4 | import android.os.AsyncTask; 5 | import android.util.Log; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import su.whs.hyphens.HyphenLineBreaker; 11 | 12 | 13 | /** 14 | * Created by igor n. boulliev on 03.04.15. 15 | */ 16 | public class wATLApp extends Application { 17 | private boolean hyphenatorReady = false; 18 | public static boolean serializationEnabled = false; 19 | private ContentLoader contentLoader = new ContentLoader(); 20 | 21 | public interface StateListener { 22 | void onHyphenatorLoaded(); 23 | } 24 | 25 | @Override 26 | public void onCreate() { 27 | super.onCreate(); 28 | new AsyncTask() { 29 | 30 | @Override 31 | protected void onPreExecute() { 32 | hyphenatorReady = false; 33 | } 34 | 35 | @Override 36 | protected Void doInBackground(Void... params) { 37 | /** loading patterns from assets **/ 38 | HyphenLineBreaker.require(getApplicationContext(),"en_us"); 39 | hyphenatorReady = true; 40 | return null; 41 | } 42 | 43 | 44 | 45 | @Override 46 | protected void onPostExecute(Void params) { 47 | notifyListeners(); 48 | } 49 | }.execute(); 50 | 51 | // /** benchmark **/ 52 | // contentLoader.removeCachedVersion(getBaseContext(),ContentLoader.ARTICLE_SCIENCE1); 53 | // long start = SystemClock.uptimeMillis(); 54 | // for(int i=0; i<100; i++) { 55 | // ContentLoader.Article a = contentLoader.get(ContentLoader.ARTICLE_SCIENCE1); 56 | // try { 57 | // a.load(getApplicationContext(), new ArticleView() { 58 | // @Override 59 | // public void setLoadingState(boolean state, int percents) { 60 | // 61 | // } 62 | // 63 | // @Override 64 | // public void setContent(String title, String author, String source, CharSequence content) { 65 | // 66 | // } 67 | // }); 68 | // } catch (Exception e) { 69 | // Log.e("App", "benchmark failed"); 70 | // e.printStackTrace(); 71 | // return; 72 | // } 73 | // } 74 | // long spent = SystemClock.uptimeMillis() - start; 75 | // Log.e("APP:PERF", "100 loads: "+String.valueOf(spent)+" ms"); 76 | // start = SystemClock.uptimeMillis(); 77 | if (serializationEnabled) { 78 | contentLoader.cacheArticleAsSerializedSpanned(getApplicationContext(), new Runnable() { 79 | @Override 80 | public void run() { 81 | Log.d("wATLApp", "serialization finished"); 82 | } 83 | }); 84 | } 85 | // spent = SystemClock.uptimeMillis() - start; 86 | // Log.e("APP:PERF", "caching time spent: " + String.valueOf(spent) + " ms"); 87 | // start = SystemClock.uptimeMillis(); 88 | // for(int i=0; i<100; i++) { 89 | // ContentLoader.Article a = contentLoader.get(ContentLoader.ARTICLE_SCIENCE1); 90 | // try { 91 | // a.load(getApplicationContext(),new ArticleView() { 92 | // @Override 93 | // public void setLoadingState(boolean state, int percents) { 94 | // 95 | // } 96 | // 97 | // @Override 98 | // public void setContent(String title, String author, String source, CharSequence content) { 99 | // 100 | // } 101 | // }); 102 | // } catch (Exception e) { 103 | // // e.printStackTrace(); 104 | // Log.e("APP:PERF", "benchmark failed"); 105 | // e.printStackTrace(); 106 | // return; 107 | // } 108 | // } 109 | // spent = SystemClock.uptimeMillis() - start; 110 | // Log.e("APP:PERF", "100 deserialization time spent: "+String.valueOf(spent)+" ms"); 111 | } 112 | 113 | List mStateListeners = new ArrayList(); 114 | 115 | public void addStateListener(StateListener listener) { 116 | synchronized (this) { 117 | if (!mStateListeners.contains(listener)) 118 | mStateListeners.add(listener); 119 | if (hyphenatorReady) 120 | listener.onHyphenatorLoaded(); 121 | } 122 | } 123 | 124 | public void removeStateListener(StateListener listener) { 125 | synchronized (this) { 126 | if (mStateListeners.contains(listener)) 127 | mStateListeners.remove(listener); 128 | } 129 | } 130 | 131 | private void notifyListeners() { 132 | if (hyphenatorReady) 133 | synchronized (this) { 134 | for(StateListener listener : mStateListeners) 135 | listener.onHyphenatorLoaded(); 136 | } 137 | } 138 | 139 | public void getArticle(final String uuid, final ArticleView view) { 140 | new AsyncTask() { 141 | 142 | @Override 143 | protected void onPreExecute() { 144 | super.onPreExecute(); 145 | 146 | } 147 | 148 | @Override 149 | protected ContentLoader.Article doInBackground(Void... params) { 150 | ContentLoader.Article article = contentLoader.get(uuid); 151 | 152 | return article; 153 | } 154 | 155 | @Override 156 | protected void onPostExecute(ContentLoader.Article article) { 157 | try { 158 | article.load(getApplicationContext(),view); 159 | view.setLoadingState(false,100); 160 | } catch (Exception e) { 161 | view.setContent(null,null,null,"error reading article: " + e.toString()); 162 | } 163 | } 164 | }.execute(); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /app/src/main/assets/articles/science2a.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
Wild Things
5 |
6 | 7 |
8 |
9 | 10 | 11 | 12 |
13 |

These birds provide their own drum beat

14 |
15 | 16 | 17 | 18 |
19 |
java sparrow

Male Java sparrows integrate beak clicks into their songs, a new study reveals. 

Listen closely to a Java sparrow sing: Interspersed among the notes will be clicks that the bird makes with its bill. All male birds use the clicking sounds in their songs — and the patterns appear to be passed from father to son, a new study reports.

Masayo Soma and Chihiro Mori of the Hokkaido University in Japan analyzed recordings of 30 male birds. These were a domesticated version of the species Lonchura oryzivora, which is native to the Indonesian islands of Java and Bali (and on the decline because so many have been trapped for the pet trade). Twenty-two of the birds were related (fathers and sons or foster sons), seven were reared in isolation and the last bird grew up among Bengalese finches that don’t make clicking sounds. The results of the analysis were published May 20 in PLOS ONE.

The click sound can be produced without learning, Soma and Mori found. All the birds, including those that were reared on their own and never heard another Java sparrow, sang songs that included bill clicks at least some of the time. Older birds produced the sounds in almost every song; younger ones less often. They appeared to get the hang of the sound and incorporating it into songs by about six months of age, the researchers found.

But there was some transfer of knowledge from father to son. Within these pairs of birds, there were similarities in their songs. Fathers and sons tended to use clicking sounds at the same rate in their tunes. Sons learned 68 to 90 percent of dad’s repertoire, and those that were the best learners incorporated more clicks into what they sang.

Soma and Mori then looked at the 18 birds that clicked most often, in more than 60 percent of their songs. They found that the birds tended to click more frequently at the beginning of songs and before and after specific notes. The clicks appear to be integral parts of certain syllables within the songs, the researchers say.

“The question of why Java sparrows use nonvocal sound communication in addition to singing remains a puzzle,” the team writes. Female birds also make the sounds, but their vocalizations have yet to be analyzed. The clicks may be involved in courting, but it’s unclear for now how such a complex communication system evolved.

37 |
40 | 41 | 44 |
-------------------------------------------------------------------------------- /app/src/main/assets/articles/rtl_test.html: -------------------------------------------------------------------------------- 1 |

אנדרואידאנגלית: Android) היא מערכת הפעלה המיועדת לסמארטפונים, טאבלטים, טלויזיות חכמות, שעונים חכמים ולמכוניות ומבוססת על ליבת לינוקס. היא מופצת על ידי חברת גוגל בשיתוף פעולה עם Open Handset Alliance. מערכת הפעלה זו מעוצבת במיוחד לשימוש בטלפונים חכמים מבוססי מסך מגע ומחשבי לוח (טאבלטים). לקראת סוף שנת 2010, אנדרואיד הפכה למערכת ההפעלה הנפוצה ביותר בעולם לטלפונים חכמים. על פי IDC, ב-2012 היא החזיקה נתח של 70% מכלל שוק הטלפונים החכמים העולמי (ביחס לכ-20% למתחרה המרכזית iOS של חברת אפל) ובמהלך השנה נמכרו כמעט 500 מיליון מכשירים חדשים מבוססי אנדרואיד. סמארטפונים מפורסמים עם אנדרואיד הם מכשירים בסדרת "גלקסי" של סמסונג ושל חברת סוני אריקסון או של חברות סיניות וגם חברת מוטורולה ו HTC‏[1].

2 |
3 |

بداية النظام[عدل]

4 |

تأسست أندرويد (Android) في بالو ألتو، كاليفورنيا (Palo Alto, California) في أكتوبر 2003 من قبل أندي روبين (Andy Rubin) المؤسس المشارك Danger)، وريتش مينر (Rich Miner) المؤسس المشارك Wildfire Communications, Inc.)، ونيك سيرز(NickSears) (أحد نوَاب رئيس T-Mobile) وكريس وايت (Chris White) رئيس تصميم الواجهات في (WebTV) لتطوير "أجهزة نقالة أكثر ذكاء ومعرفةً بمكان مالكها وتفضيلاته الخاصة". كما قال أندي روبين (Andy Rubin) . كانت نوايا الشركة أن تطور نظام تشغيل متقدم للكاميرات الرقمية، وعندما تبين أن سوق الكاميرات الرقمية ليس كبير بما فيه الكفاية، حولوا جهودهم لإنتاج نظام تشغيل للهواتف الذكية لمنافسة انظمة سيمبيان (Symbian) وويندوز موبايل (Windows Mobile) (لم يكن نظام iOS الخاص بتشغيل أجهزةIPhone موجودا في ذلك الوقت). وعلى الرغم من الإنجازات التي قام بها المؤسسين والموظفين في وقت مبكر، إلا أنهم كانوا يعملون سرا، ولم يكشفوا إلا عن أنهم يعملون على برمجيات للهواتف النقالة.

5 |

شراء جوجل للنظام[عدل]

6 |

في أغسطس 2005، قامت شركة جوجل بشراء النظام من الشركة المالكة وضم المؤسسين السابقين وعلى رأسهم المهندس أندرو روبن الذي استمر بالعمل على تطوير النظام، ويعتبر هو المسؤول المباشر عن وصول نظام أندرويد إلى النجاح الذي نشهده حالياً.

7 |

أصل الكلمة[عدل]

8 |

كلمة android الإنجليزية تعني الإنسان الآلي الذي يكون على شكل إنسان (الإنسالة).

9 |

المميزات[عدل]

10 | 15 |

الواجهة[عدل]

16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |

واجهة نظام أندرويد مبنية على التلاعب المباشر[1]. الاستجابة للمسات الواجهة مبنية لتكون فوريَّة.

24 |

التطبيقات[عدل]

25 | 30 |

متجر جوجل بلاي هو متجر على الويب للبرامج تديره جوجل لأجهزة أندرويد، التطبيق "Google play" مثبت على معظم أجهزة أندرويد، حتى اغسطس 2013 هناك 900,000 تطبيق وجدت في المتجر. جوجل لديها العديد من البرامج في المتجر منها Googles وEarth وSkymap وBBM

31 |

على عكس معظم الأنظمة الأخرى، يسمح نظام الأندرويد بتنصيب متاجر تطبيقات بديلة، من أشهر هذه المتاجر متجر أمازون المسمى Amazon Appstore

32 |
33 |
المجانية
34 |
يعتبر نظام أندرويد أكثر نظام مجاني حيث التطبيقات المجانية فيه يفوق عددها التطبيقات المدفوعة.
35 |
36 |
37 |
الويدجيت
38 |
39 |
40 |
هي تطبيقات صغيرة توجد على واجهة المستخدم مثل : تطبيق حي لحالة الطقس في الوقت الحالي، صندوق البريد الإلكتروني للمستخدم
41 |
42 |

التخزين

-------------------------------------------------------------------------------- /syllabification/src/androidTest/java/su/whs/hyphens/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package su.whs.hyphens; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import su.whs.syllabification.parent.LineBreaker; 14 | 15 | import static org.junit.Assert.*; 16 | 17 | /** 18 | * Instrumentation test, which will execute on an Android device. 19 | * 20 | * @see Testing documentation 21 | */ 22 | @RunWith(AndroidJUnit4.class) 23 | public class ExampleInstrumentedTest { 24 | @Test 25 | public void useAppContext() throws Exception { 26 | // Context of the app under test. 27 | Context appContext = InstrumentationRegistry.getTargetContext(); 28 | 29 | assertEquals("su.whs.hyphens.test", appContext.getPackageName()); 30 | } 31 | 32 | @Test 33 | public void testIsPunctionation() { 34 | 35 | for(int i=0; i stack = new ArrayList(); 60 | List results = new ArrayList(); 61 | int previousBreakPosition = -1; 62 | for(int i=0; isource.length()) { 74 | throw new RuntimeException(String.format( 75 | "%s\nbreak position = %d\ni=%d, ch='%s'\n", source, pos, i, ch 76 | )); 77 | } 78 | 79 | 80 | char test = valids.charAt(pos); 81 | 82 | if (test=='I') { 83 | throw new RuntimeException(String.format( 84 | "%s\nbreak position = %d\ni=%d, ch='%s'\n", source, pos, i, ch 85 | )); 86 | } else if (test=='H' && !LineBreaker.isHyphen(breakPoint)) { 87 | throw new RuntimeException(String.format( 88 | "%s\nbreak position = %d\ni=%d, ch='%s' - expcted HYPHEN\n", source, pos, i, ch 89 | )); 90 | } 91 | } 92 | StringBuilder sb = new StringBuilder(source); 93 | for(int p : stack) { 94 | sb.insert(p,'-'); 95 | } 96 | System.out.printf("%s\n",sb.toString()); 97 | sb = new StringBuilder(source); 98 | for(int i=0; i< source.length(); i++) 99 | sb.replace(i,i+1,"I"); 100 | for(int p : stack) { 101 | sb.replace(p,p+1,"H"); 102 | } 103 | for(int p : results) { 104 | sb.replace(p,p+1,"V"); 105 | } 106 | System.out.printf("%s\n",sb.toString()); 107 | } 108 | 109 | 110 | /** 111 | * tests 112 | **/ 113 | 114 | // 0 1 2 3 4 5 6 7 115 | static String TS0 = "Hello, world. 1234567, and 1002.045 and p.193 (A4320.4) and 23/45."; 116 | static String VS0 = "VVVVVIVVVVVVIVVIIIIIIIVVVVVVIIIIIIIVVVVVVIIIIVVIIIIIIIIVVVVVVIIIII"; 117 | static String TS1 = "Transforming nerve cells into light-sensing cells aims to restore sight in some blind patients."; 118 | static String VS1 = "VIIIIHIIIHIIVVIIIIVVIIIIVVIIIVVIIIVIVIIIHIIVVIIIIVVIIIVVIVVIIIIIIVVIIIIVVIVVIIIVVIIIIVVIIIIIIII"; 119 | static String TS2 = "This simple form is powered by hyphen library, a part of hunspell project."; 120 | static String VS2 = "VIIIVVIIHIIVVIIIVVIVVIIVIIIVVIVVVVIIIVVVVIIIIIVVVVIIIVVIVVIVVIIIIVVIVVIIII"; 121 | static String TS3 = "Biographers attempting to account for this period have reported many apocryphal stories. Nicholas Rowe, Shakespeare's first biographer, recounted a Stratford legend that Shakespeare fled the town for London to escape prosecution for deer poaching in the estate of local squire Thomas Lucy. Shakespeare is also supposed to have taken his revenge on Lucy by writing a scurrilous ballad about him."; 122 | static String VS3 = "VIIIHIHIIIIVVIIIIIIHIIVVIVVIIIIIIVVIIVVIIIVVIIIHIVVIIIVVIIIIIHIVVIIIVVIIIHIIIIIVVIIHIIIVVVIIIIIIIVVIIIIVVIIIIHIIIIIVHVVIIIIVVIIIHIHIHIVVVIIIIIIHIVVVVIIIIHIIIVVIIHIIVVIIIVVIIIIHIIIIIVVIIIVVIIVVIIIVVIIVVIIHIIVVIVVIIIIIVVIIIHHIHIIIVVIIVVIIIVVIIIIHIIVVIVVIIVVIIIIIVVIVVIIIIVVIIIIIVVIIIIIVVIIIIVVIIIIHIIIIIVVIVVIIIVVIIHIIIIVVIVVIIIVVIIHIVVIIVVIIIIIIVVIVVIIIVVIVVIIIHIIVVVVIIIHIIIIIVVIIHIIVVIIIIVVIIV"; 123 | static String TS4 = "Хотя не сохранилось записей о посещении, Шекспир вероятно получил образование в новой королевской школе в Стратфорде,[1] бесплатной школе, удалённой на около четверти мили от его дома. Школы грамоты елизаветинской эпохи варьировали качество обучения, но оно было стандантизировано королевским указом,[2] и школа точно должна была дать сильное образование в области латинской грамматики и литературы. Частью обучения была постановка учениками латинской пьесы для лучшего понимания языка.\n" + 124 | "В период, когда Шекспир вероятно постоянно проживал в Стратфорде, театральные труппы посетили город по меньшей мере 12 раз, в том числе 2 раза выступая перед чиновниками, в числе которых был отец Шекспира, который, как судебный пристав, должен был до выступления труппы пролицензировать её."; 125 | static String VS4 = "VIIIVVIVVIIIIHIHIIIVVIIIHIIVVVVIIIHIHIHVVVIIIHIHVVIIIHIHIVVIIIHIHVVIIIHIHIHIHVVVVIIIIVVIIIHIIHIIIVVIIHIVVVVIIIIHIIHIVVVIVVIIHIIIHIIVVIIHIVVVIIHIIHIIVVIVVIIHIVVIIHIIHIVVIIIVVIVVIIVVIIIIVVIIHIVVIIHIHIVVIIHIHIHIIHIIIVVIIHIVVIIIIHIHIHIVVIIIHIIIVVIIHIHIHVVVIVVIIVVIIIVVIIIHIIHIHIHIHIHIVVIIIHIIHIIHVVIIHIHVVVIVVVVIIHIVVIIHIVVIIIHIVVIIIVVIIIVVIIIHIHVVIIIHIHIHIHVVVVIIIHIIVVIIIIHIIIVVIIIHIHIHIVVVVIIIHIHIHIVVVIIIIIVVIIHIHIHVVIIIVVIIIIHIIHIVVIIHIHIHIVVIIIIHIIIVVIIHIVVIIVVIIHIHIVVIIIHIHIHVVIIHIVVVVVIIIHIVVVIIIIVVIIIHIHVVIIIHIHIVVIIIIHIHIVVIIHIHIIVVVVIIIIHIIHIVVVIIIHIIIHIHVVIIIHIVVIIIHIHIVVIIIIVVIVVIIIHIIVVIIIVVIVVIIVVVVVIIVVIIHIVVVVIIIVVIIIIHIHVVIIIIVVIIIIHIHIHIVVVVVIIHIVVIIIHIIVVIIVVIIHVVIIIHIHIVVVIIIHIIVVVIIVVIIIIHIIVVIIHIIIVVVIIHIIVVIIVVIVVIIIIIHIHIHVVIIIHIVVIIHIHIIHIHIHIIIVVIV"; 126 | 127 | 128 | static String P0 = ",.!?#$%()'\""; 129 | // 1 3 5 7 9 B D F H J L N P R T V X Z 130 | 131 | @SuppressWarnings(value = "unused") 132 | static String stubValids(String source) { 133 | StringBuilder sb = new StringBuilder(source); 134 | for(int i=0; i