Add basic readability highlighting
Personally, I'm a terrible writer and I've found simple aids really help keep my prose tight. These changes will highlight sentences that are hard to read, based on the number of syllables they contain. Here's what happens based on syllable count: - less than 25 syllables: its easy to read (heuristically speaking), and has no background colour - between 25 and 35 syllables, it's a bit hard to understand, and has a yellow background colour - over 35 syllables, its quite hard to read, and has a red background color This might be well outside the scope of what you had in mind, but I personally find it usefull. At the moment it's on by default, in a seperate observer. Maybe you could add add a setting for it
This commit is contained in:
parent
86edda5e24
commit
a4d9a9b9d7
14 changed files with 378 additions and 54 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -5,13 +5,9 @@
|
||||||
/.idea/libraries
|
/.idea/libraries
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build
|
/build
|
||||||
IAP5Helper/build
|
|
||||||
/captures
|
/captures
|
||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.idea/
|
.idea/
|
||||||
app/standard
|
|
||||||
app/samsung
|
|
||||||
*~
|
*~
|
||||||
*.log
|
*.log
|
||||||
app/acra.properties
|
|
||||||
keystore.properties
|
keystore.properties
|
||||||
|
|
38
.gitlab-ci.yml
Normal file
38
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
image: openjdk:8-jdk
|
||||||
|
|
||||||
|
variables:
|
||||||
|
ANDROID_COMPILE_SDK: "28"
|
||||||
|
ANDROID_BUILD_TOOLS: "28.0.3"
|
||||||
|
ANDROID_SDK_TOOLS: "4333796"
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export GRADLE_USER_HOME=cache/.gradle
|
||||||
|
- apt-get --quiet update --yes
|
||||||
|
- apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1
|
||||||
|
- wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip
|
||||||
|
- unzip -d android-sdk-linux android-sdk.zip
|
||||||
|
- echo y | android-sdk-linux/tools/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" >/dev/null
|
||||||
|
- echo y | android-sdk-linux/tools/bin/sdkmanager "platform-tools" >/dev/null
|
||||||
|
- echo y | android-sdk-linux/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" >/dev/null
|
||||||
|
- export ANDROID_HOME=$PWD/android-sdk-linux
|
||||||
|
- export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/
|
||||||
|
- chmod +x ./gradlew
|
||||||
|
# temporarily disable checking for EPIPE error and use yes to accept all licenses
|
||||||
|
- set +o pipefail
|
||||||
|
- yes | android-sdk-linux/tools/bin/sdkmanager --licenses
|
||||||
|
- set -o pipefail
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- test
|
||||||
|
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- ./gradlew --stacktrace --console=plain :app:lintDebug jacocoTestReport
|
||||||
|
- cat app/build/reports/jacoco/jacocoTestReport/html/index.html
|
||||||
|
artifacts:
|
||||||
|
reports:
|
||||||
|
junit: app/build/test-results/testDebugUnitTest/TEST-*.xml
|
||||||
|
paths:
|
||||||
|
- app/build/reports/jacoco/jacocoTestReport/
|
||||||
|
- app/build/outputs/
|
|
@ -1,6 +1,7 @@
|
||||||
# [Simple Markdown](https://wbrawner.com/portfolio/simple-markdown/)
|
# [Simple Markdown](https://wbrawner.com/portfolio/simple-markdown/)
|
||||||
|
|
||||||
[![Build Status](https://ci.wbrawner.com/job/Simple%20Markdown/badge/icon)](https://ci.wbrawner.com/job/Simple%20Markdown/)
|
[![pipeline status](https://gitlab.com/billybrawner/SimpleMarkdown/badges/master/pipeline.svg)](https://gitlab.com/billybrawner/SimpleMarkdown/commits/master)
|
||||||
|
[![coverage report](https://gitlab.com/billybrawner/SimpleMarkdown/badges/master/coverage.svg)](https://gitlab.com/billybrawner/SimpleMarkdown/commits/master)
|
||||||
|
|
||||||
Simple Markdown is simply a Markdown editor :) I wrote it to offer up an open source alternative to
|
Simple Markdown is simply a Markdown editor :) I wrote it to offer up an open source alternative to
|
||||||
the other Markdown editors available on the Play Store. I also wanted to get some practice in
|
the other Markdown editors available on the Play Store. I also wanted to get some practice in
|
||||||
|
@ -27,8 +28,7 @@ Using Android Studio is the preferred way to build the project. To build from th
|
||||||
### Crashlytics
|
### Crashlytics
|
||||||
|
|
||||||
SimpleMarkdown makes use of Firebase Crashlytics for error reporting. You'll need to follow the
|
SimpleMarkdown makes use of Firebase Crashlytics for error reporting. You'll need to follow the
|
||||||
[Get started with Firebase Crashlytics](https://firebase.google
|
[Get started with Firebase Crashlytics](https://firebase.google.com/docs/crashlytics/get-started?platform=android) guide in order to build the project.
|
||||||
.com/docs/crashlytics/get-started?platform=android) guide in order to build the project.
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
2
app/.gitignore
vendored
2
app/.gitignore
vendored
|
@ -1,4 +1,2 @@
|
||||||
/build
|
/build
|
||||||
crashlytics.properties
|
|
||||||
*.apk
|
*.apk
|
||||||
google-services.json
|
|
|
@ -3,10 +3,20 @@ apply plugin: 'kotlin-android-extensions'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'io.fabric'
|
apply plugin: 'io.fabric'
|
||||||
|
apply plugin: 'jacoco'
|
||||||
|
|
||||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
try {
|
||||||
|
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
logger.warn("Unable to load keystore properties. Automatic signing won't be available")
|
||||||
|
keystoreProperties['keyAlias'] = ""
|
||||||
|
keystoreProperties['keyPassword'] = ""
|
||||||
|
keystoreProperties['storeFile'] = File.createTempFile("temp", ".tmp").absolutePath
|
||||||
|
keystoreProperties['storePassword'] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
configurations.all {
|
configurations.all {
|
||||||
|
@ -44,6 +54,9 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
testCoverageEnabled true
|
||||||
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
@ -96,9 +109,36 @@ dependencies {
|
||||||
implementation "androidx.core:core-ktx:1.0.2"
|
implementation "androidx.core:core-ktx:1.0.2"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
|
||||||
|
implementation 'eu.crydee:syllable-counter:4.0.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jacoco {
|
||||||
|
toolVersion = '0.8.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
jacoco.includeNoLocationClasses = true
|
||||||
|
}
|
||||||
|
|
||||||
|
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
def fileFilter = [ '**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*' ]
|
||||||
|
def javaDebugTree = fileTree(dir: "$project.buildDir/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileFilter)
|
||||||
|
def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
|
||||||
|
def mainSrc = "$project.projectDir/src/main/java"
|
||||||
|
|
||||||
|
sourceDirectories = files([mainSrc])
|
||||||
|
classDirectories = files([javaDebugTree, kotlinDebugTree])
|
||||||
|
executionData = fileTree(dir: project.buildDir, includes: [
|
||||||
|
'jacoco/testDebugUnitTest.exec', 'outputs/code-coverage/connected/*coverage.ec'
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
78
app/google-services.json
Normal file
78
app/google-services.json
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "318641233555",
|
||||||
|
"firebase_url": "https://simplemarkdown.firebaseio.com",
|
||||||
|
"project_id": "simplemarkdown",
|
||||||
|
"storage_bucket": "simplemarkdown.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:318641233555:android:09d865cad87e3b5f",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.wbrawner.simplemarkdown"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "318641233555-83n2k1mqhokf0b7lhccqiva9pspgripq.apps.googleusercontent.com",
|
||||||
|
"client_type": 1,
|
||||||
|
"android_info": {
|
||||||
|
"package_name": "com.wbrawner.simplemarkdown",
|
||||||
|
"certificate_hash": "710e37c230689bc259fc6e2e032e2f56956f8d33"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBDMcXg-10NsXLDKJRtj5WnXoHrwg3m9Os"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"admob_app_id": "ca-app-pub-3319579963502409~4576405307"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:318641233555:android:5dfb62206717437e",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.wbrawner.simplemarkdown.samsung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBDMcXg-10NsXLDKJRtj5WnXoHrwg3m9Os"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.wbrawner.simplemarkdown.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Readability {
|
||||||
|
private String content;
|
||||||
|
private static final String DELIMS = ".!?\n";
|
||||||
|
|
||||||
|
public Readability(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Sentence> sentences() {
|
||||||
|
|
||||||
|
ArrayList<Sentence> list = new ArrayList<>();
|
||||||
|
|
||||||
|
int startOfSentance = 0;
|
||||||
|
StringBuilder lineBuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < content.length(); i++) {
|
||||||
|
String c = content.charAt(i) + "";
|
||||||
|
if (DELIMS.contains(c)) {
|
||||||
|
list.add(new Sentence(content, startOfSentance, i));
|
||||||
|
startOfSentance = i + 1;
|
||||||
|
lineBuilder = new StringBuilder();
|
||||||
|
} else {
|
||||||
|
lineBuilder.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String line = lineBuilder.toString();
|
||||||
|
if (!line.isEmpty()) list.add(new Sentence(content, startOfSentance, content.length()));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.wbrawner.simplemarkdown.model;
|
||||||
|
|
||||||
|
import eu.crydee.syllablecounter.SyllableCounter;
|
||||||
|
|
||||||
|
public class Sentence {
|
||||||
|
|
||||||
|
private String sentence = "";
|
||||||
|
private int start = 0;
|
||||||
|
private int end = 0;
|
||||||
|
|
||||||
|
private final static SyllableCounter sc = new SyllableCounter();
|
||||||
|
|
||||||
|
public Sentence(String content, int start, int end){
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.sentence = content.substring(start, end);
|
||||||
|
|
||||||
|
trimStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sentence(String sentence){
|
||||||
|
this.sentence = sentence;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trimStart() {
|
||||||
|
while(sentence.startsWith(" ")){
|
||||||
|
this.start++;
|
||||||
|
sentence = sentence.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return sentence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int start(){
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int end(){
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int syllableCount(){
|
||||||
|
return sc.count(sentence);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.wbrawner.simplemarkdown.utility;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.style.BackgroundColorSpan;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.model.Readability;
|
||||||
|
import com.wbrawner.simplemarkdown.model.Sentence;
|
||||||
|
|
||||||
|
import io.reactivex.Observer;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
|
public class ReadabilityObserver implements Observer<String> {
|
||||||
|
private EditText text;
|
||||||
|
private String previousValue = "";
|
||||||
|
|
||||||
|
public ReadabilityObserver(EditText text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(Disposable d) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(String markdown) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
if (markdown.length() < 1) return;
|
||||||
|
if (previousValue.equals(markdown)) return;
|
||||||
|
Readability readability = new Readability(markdown);
|
||||||
|
SpannableString span = new SpannableString(markdown);
|
||||||
|
for (Sentence sentence : readability.sentences()) {
|
||||||
|
int color = Color.TRANSPARENT;
|
||||||
|
if (sentence.syllableCount() > 25) color = Color.argb(100, 229, 232, 42);
|
||||||
|
if (sentence.syllableCount() > 35) color = Color.argb(100, 193, 66, 66);
|
||||||
|
span.setSpan(new BackgroundColorSpan(color), sentence.start(), sentence.end(), 0);
|
||||||
|
}
|
||||||
|
text.setTextKeepState(span, TextView.BufferType.SPANNABLE);
|
||||||
|
previousValue = markdown;
|
||||||
|
long timeTakenMs = System.currentTimeMillis() - start;
|
||||||
|
Log.d("SimpleMarkdown", "Handled markdown in " + timeTakenMs + "ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable e) {
|
||||||
|
System.err.println("An error occurred while handling the markdown");
|
||||||
|
e.printStackTrace();
|
||||||
|
// TODO: report this?
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package com.wbrawner.simplemarkdown.view.fragment
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.preference.PreferenceManager
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -17,6 +18,7 @@ import com.wbrawner.simplemarkdown.MarkdownApplication
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter
|
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter
|
||||||
import com.wbrawner.simplemarkdown.utility.MarkdownObserver
|
import com.wbrawner.simplemarkdown.utility.MarkdownObserver
|
||||||
|
import com.wbrawner.simplemarkdown.utility.ReadabilityObserver
|
||||||
import com.wbrawner.simplemarkdown.view.MarkdownEditView
|
import com.wbrawner.simplemarkdown.view.MarkdownEditView
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
@ -48,6 +50,16 @@ class EditFragment : Fragment(), MarkdownEditView {
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
obs.subscribe(MarkdownObserver(presenter, obs))
|
obs.subscribe(MarkdownObserver(presenter, obs))
|
||||||
|
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
val enableReadability = sharedPrefs.getBoolean(getString(R.string.readability_enabled), false)
|
||||||
|
if (enableReadability) {
|
||||||
|
val readabilityObserver = RxTextView.textChanges(markdownEditor!!)
|
||||||
|
.debounce(250, TimeUnit.MILLISECONDS)
|
||||||
|
.map { it.toString() }
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
readabilityObserver.subscribe(ReadabilityObserver(markdownEditor))
|
||||||
|
}
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +101,7 @@ class EditFragment : Fragment(), MarkdownEditView {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setMarkdown(markdown: String) {
|
override fun setMarkdown(markdown: String) {
|
||||||
markdownEditor!!.setText(markdown)
|
markdownEditor?.setText(markdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTitle(title: String) {
|
override fun setTitle(title: String) {
|
||||||
|
|
|
@ -40,6 +40,10 @@
|
||||||
<string name="pref_title_error_reports">Enable automated error reports</string>
|
<string name="pref_title_error_reports">Enable automated error reports</string>
|
||||||
<string name="pref_error_reports_off">Error reports will not be sent</string>
|
<string name="pref_error_reports_off">Error reports will not be sent</string>
|
||||||
<string name="pref_error_reports_on">Error reports will be sent</string>
|
<string name="pref_error_reports_on">Error reports will be sent</string>
|
||||||
|
<string name="readability_enabled">readability.enable</string>
|
||||||
|
<string name="pref_title_readability">Enable readability highlighting (experimental)</string>
|
||||||
|
<string name="pref_readability_off">Readability highlighting is off</string>
|
||||||
|
<string name="pref_readability_on">Readability highlighting is on</string>
|
||||||
<string name="pref_autosave_on">Files will automatically save</string>
|
<string name="pref_autosave_on">Files will automatically save</string>
|
||||||
<string name="pref_autosave_off">Files will not be automatically saved</string>
|
<string name="pref_autosave_off">Files will not be automatically saved</string>
|
||||||
<string name="pref_custom_css">pref.custom_css</string>
|
<string name="pref_custom_css">pref.custom_css</string>
|
||||||
|
|
|
@ -23,5 +23,11 @@
|
||||||
android:summaryOff="@string/pref_error_reports_off"
|
android:summaryOff="@string/pref_error_reports_off"
|
||||||
android:summaryOn="@string/pref_error_reports_on"
|
android:summaryOn="@string/pref_error_reports_on"
|
||||||
android:title="@string/pref_title_error_reports" />
|
android:title="@string/pref_title_error_reports" />
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/readability_enabled"
|
||||||
|
android:summaryOff="@string/pref_readability_off"
|
||||||
|
android:summaryOn="@string/pref_readability_on"
|
||||||
|
android:title="@string/pref_title_readability" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.wbrawner.simplemarkdown;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.model.Readability;
|
||||||
|
import com.wbrawner.simplemarkdown.model.Sentence;
|
||||||
|
import eu.crydee.syllablecounter.SyllableCounter;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class ReadabilityTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void break_content_into_sentances() {
|
||||||
|
SyllableCounter sc = new SyllableCounter();
|
||||||
|
assertEquals(4, sc.count("facility"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_break_text_into_sentences_with_indexes(){
|
||||||
|
String content = "Hop on pop. I am a fish. This is a test.";
|
||||||
|
Readability readability = new Readability(content);
|
||||||
|
List<Sentence> sentenceList = readability.sentences();
|
||||||
|
|
||||||
|
assertEquals(3, sentenceList.size());
|
||||||
|
|
||||||
|
Sentence hopOnPop = sentenceList.get(0);
|
||||||
|
assertEquals(hopOnPop.toString(), "Hop on pop");
|
||||||
|
assertEquals(0, hopOnPop.start());
|
||||||
|
assertEquals(10, hopOnPop.end());
|
||||||
|
|
||||||
|
Sentence iAmAFish = sentenceList.get(1);
|
||||||
|
assertEquals(iAmAFish.toString(), "I am a fish");
|
||||||
|
assertEquals(12, iAmAFish.start());
|
||||||
|
assertEquals(23, iAmAFish.end());
|
||||||
|
|
||||||
|
Sentence thisIsATest = sentenceList.get(2);
|
||||||
|
assertEquals(thisIsATest.toString(), "This is a test");
|
||||||
|
assertEquals(25, thisIsATest.start());
|
||||||
|
assertEquals(39, thisIsATest.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void get_syllable_count_for_sentence(){
|
||||||
|
assertEquals(8, new Sentence("This is the song that never ends").syllableCount());
|
||||||
|
assertEquals(10, new Sentence("facility facility downing").syllableCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -15,9 +15,7 @@ import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@ -42,46 +40,6 @@ public class UtilsTest {
|
||||||
rmdir(new File(rootDir));
|
rmdir(new File(rootDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDocsPath() throws Exception {
|
|
||||||
sharedPreferences.edit().putString(Constants.KEY_DOCS_PATH, rootDir).apply();
|
|
||||||
assertEquals(rootDir, Utils.getDocsPath(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDefaultFileName() throws Exception {
|
|
||||||
sharedPreferences.edit().putString(Constants.KEY_DOCS_PATH, rootDir).apply();
|
|
||||||
|
|
||||||
new File(rootDir, "dummy.md").createNewFile();
|
|
||||||
new File(rootDir, "dummy1.md").createNewFile();
|
|
||||||
new File(rootDir, "Untitled-a.md").createNewFile();
|
|
||||||
|
|
||||||
String firstDefaultName = Utils.getDefaultFileName(context);
|
|
||||||
assertEquals("Untitled.md", firstDefaultName);
|
|
||||||
File firstFile = new File(rootDir, firstDefaultName);
|
|
||||||
firstFile.createNewFile();
|
|
||||||
|
|
||||||
String secondDefaultName = Utils.getDefaultFileName(context);
|
|
||||||
assertEquals("Untitled-1.md", secondDefaultName);
|
|
||||||
File secondFile = new File(rootDir, secondDefaultName);
|
|
||||||
secondFile.createNewFile();
|
|
||||||
|
|
||||||
String thirdDefaultName = Utils.getDefaultFileName(context);
|
|
||||||
assertEquals("Untitled-2.md", thirdDefaultName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDefaultFileNameDoubleDigitTest() throws IOException {
|
|
||||||
sharedPreferences.edit().putString(Constants.KEY_DOCS_PATH, rootDir).apply();
|
|
||||||
|
|
||||||
for (int i = 0; i < 11; i++) {
|
|
||||||
new File(rootDir, "Untitled-" + i + ".md").createNewFile();
|
|
||||||
}
|
|
||||||
assertTrue(new File(rootDir, "Untitled-10.md").exists());
|
|
||||||
String defaultName = Utils.getDefaultFileName(context);
|
|
||||||
assertEquals("Untitled-11.md", defaultName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isAutosaveEnabled() throws Exception {
|
public void isAutosaveEnabled() throws Exception {
|
||||||
assertTrue(Utils.isAutosaveEnabled(context));
|
assertTrue(Utils.isAutosaveEnabled(context));
|
||||||
|
|
Loading…
Reference in a new issue