Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/orgzly/orgzly-android
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas Harrison committed Nov 27, 2021
2 parents 1ef1b1b + c010310 commit 1a9225e
Show file tree
Hide file tree
Showing 124 changed files with 1,767 additions and 700 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/android-build-master.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build on PR Create or Merge
name: Build

on:
pull_request:
Expand All @@ -7,18 +7,20 @@ on:
push:
branches:
- 'master'
- 'release-*'

jobs:
build:
name: Generate APK
runs-on: ubuntu-18.04

steps:
- uses: actions/checkout@v1
- name: Setup JDK 1.8
uses: actions/setup-java@v1
- uses: actions/checkout@v2
- name: Setup JDK
uses: actions/setup-java@v2
with:
java-version: 1.8
distribution: 'zulu'
java-version: '11'
- name: Build APK
run: ./gradlew assembleDebug
- name: Upload APK
Expand Down
12 changes: 3 additions & 9 deletions README.org
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#+BEGIN_HTML
<a title="Build" target="_blank" href="https://github.com/orgzly/orgzly-android/actions/workflows/android-build-master.yml"><img src="https://github.com/orgzly/orgzly-android/actions/workflows/android-build-master.yml/badge.svg"></a>
<a title="Crowdin" target="_blank" href="https://crowdin.com/project/orgzly"><img src="https://d322cqt584bo4o.cloudfront.net/orgzly/localized.svg"></a>
#+END_HTML

Expand All @@ -16,10 +17,10 @@ http://orgmode.org for more information.

#+BEGIN_HTML
<a href="https://play.google.com/store/apps/details?id=com.orgzly">
<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="70">
<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="80">
</a>
<a href="https://f-droid.org/app/com.orgzly">
<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="70">
<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="80">
</a>
#+END_HTML

Expand All @@ -38,13 +39,6 @@ example:

Make sure you [[https://developer.android.com/training/testing/espresso/setup][turn off animations]] for the device you're testing on.

Java 8 is required for command line usage. Later versions are currently not compatible.

*** Dropbox

Dropbox integration, and associated tests, are disabled in the default configuration.
To enable, follow the instructions in sample.app.properties.

** License

The project is licensed under the [[https://github.com/orgzly/orgzly-android/blob/master/LICENSE][GNU General Public License version 3 (or newer)]].
38 changes: 20 additions & 18 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,14 @@ apply plugin: 'kotlin-kapt'


android {
dexOptions {
maxProcessCount 4
javaMaxHeapSize "2g"
}

compileSdkVersion 29
compileSdkVersion 30

defaultConfig {
minSdkVersion 16 // Jelly Bean (4.1)
targetSdkVersion 29 // Android 10
targetSdkVersion 30 // Android 11
applicationId "com.orgzly"
versionCode 155
versionName "1.8.4"
versionCode 158
versionName "1.8.5"

testInstrumentationRunner "com.orgzly.android.OrgzlyTestRunner"
// testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand All @@ -26,8 +21,6 @@ android {
buildConfigField "String", "DROPBOX_APP_KEY", gradle.ext.appProperties.getProperty("dropbox.app_key", '""')
resValue "string", "dropbox_app_key_schema", gradle.ext.appProperties.getProperty("dropbox.app_key_schema", '')

buildConfigField "boolean", "IS_GIT_ENABLED", gradle.ext.appProperties.getProperty("git.enabled", 'false')

javaCompileOptions {
annotationProcessorOptions {
arguments = [
Expand Down Expand Up @@ -103,15 +96,18 @@ android {
* javax.servlet.http. Referenced from com.dropbox.core.DbxStandardSessionStore.
*/
disable 'InvalidPackage'

checkDependencies true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'plugin.properties'
}
}

Expand All @@ -134,7 +130,7 @@ dependencies {
implementation "androidx.recyclerview:recyclerview:$versions.android_recyclerview"
implementation "androidx.viewpager:viewpager:$versions.android_viewpager"
implementation "androidx.constraintlayout:constraintlayout:$versions.android_constraint_layout"
implementation "androidx.preference:preference:$versions.android_preference"
implementation "androidx.preference:preference-ktx:$versions.android_preference"
implementation "com.google.android.material:material:$versions.android_material"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:$versions.android_swiperefreshlayout"

Expand Down Expand Up @@ -196,14 +192,20 @@ dependencies {

implementation "com.github.bumptech.glide:glide:$versions.glide"

implementation("com.thegrizzlylabs.sardine-android:sardine-android:$versions.sardine") {
implementation("com.github.thegrizzlylabs:sardine-android:$versions.sardine") {
exclude group: 'xpp3', module: 'xpp3'
}

implementation("org.eclipse.jgit:org.eclipse.jgit:$versions.jgit") {
// Resolves DuplicatePlatformClasses lint error
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
constraints {
implementation('com.squareup.okhttp3:okhttp:4.10.0-RC1') {
because 'https://github.com/orgzly/orgzly-android/issues/880'
}
}

implementation "io.github.rburgst:okhttp-digest:$versions.okhttp_digest"

implementation "org.eclipse.jgit:org.eclipse.jgit:$versions.jgit"
implementation "org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:$versions.jgit"
}

repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -815,4 +815,12 @@ public void testScheduledTimestamp() {

onNotesInSearch().check(matches(recyclerViewItemCount(1)));
}

@Test
public void testNotScheduled() {
testUtils.setupBook("notebook-1", "* Note A");
ActivityScenario.launch(MainActivity.class);
searchForText("s.no");
onNotesInSearch().check(matches(recyclerViewItemCount(1)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.orgzly.android.misc

import android.os.Environment
import android.util.Log
import com.orgzly.android.OrgzlyTest
import org.junit.Test

class LogSomethingNotTest : OrgzlyTest() {
@Test
fun testLink() {
Log.i(
"XXX", String.format(
"""
Environment.getExternalStorageDirectory: %s
context.filesDir: %s
context.getExternalFilesDir(null): %s
context.getExternalFilesDir(DOWNLOADS): %s""".trimIndent(),
Environment.getExternalStorageDirectory(),
context.filesDir,
context.getExternalFilesDir(null),
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
)
);
}
}
23 changes: 15 additions & 8 deletions app/src/androidTest/java/com/orgzly/android/query/QueryTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -178,27 +178,27 @@ class QueryTest(private val param: Parameter) : OrgzlyTest() {
Parameter(
queryString = "s.le.2w",
expectedQueryString = "s.2w",
expectedSqlSelection = "((scheduled_is_active = 1 AND (scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 14+1) + ")))"
expectedSqlSelection = "((scheduled_is_active = 1 AND scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 14+1) + "))"
),
Parameter(
queryString = "s.le.3d",
expectedQueryString = "s.3d",
expectedSqlSelection = "((scheduled_is_active = 1 AND (scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 3+1) + ")))"
expectedSqlSelection = "((scheduled_is_active = 1 AND scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 3+1) + "))"
),
Parameter(
queryString = "s.le.2h",
expectedQueryString = "s.2h",
expectedSqlSelection = "((scheduled_is_active = 1 AND (scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.HOUR_OF_DAY, 2+1) + ")))"
expectedSqlSelection = "((scheduled_is_active = 1 AND scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.HOUR_OF_DAY, 2+1) + "))"
),
Parameter(
queryString = "s.le.+2h",
expectedQueryString = "s.2h",
expectedSqlSelection = "((scheduled_is_active = 1 AND (scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.HOUR_OF_DAY, 2+1) + ")))"
expectedSqlSelection = "((scheduled_is_active = 1 AND scheduled_time_timestamp != 0 AND scheduled_time_timestamp < " + TimeUtils.timeFromNow(Calendar.HOUR_OF_DAY, 2+1) + "))"
),
Parameter(
queryString = "d.tom",
expectedQueryString = "d.tomorrow",
expectedSqlSelection = "((deadline_is_active = 1 AND (deadline_time_timestamp != 0 AND deadline_time_timestamp < " + TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 1+1) + ")))"
expectedSqlSelection = "((deadline_is_active = 1 AND deadline_time_timestamp != 0 AND deadline_time_timestamp < " + TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 1+1) + "))"
),
Parameter(
queryString = "c.eq.today",
Expand Down Expand Up @@ -278,12 +278,14 @@ class QueryTest(private val param: Parameter) : OrgzlyTest() {
Parameter(
queryString = "s.ge.3d",
expectedQueryString = "s.ge.3d",
expectedSqlSelection = "((scheduled_is_active = 1 AND (scheduled_time_timestamp != 0 AND ${TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 3)} <= scheduled_time_timestamp)))"
expectedSqlSelection = "((scheduled_is_active = 1 AND scheduled_time_timestamp != 0 AND ${TimeUtils.timeFromNow(Calendar.DAY_OF_MONTH, 3)} <= scheduled_time_timestamp))"
),
Parameter(
queryString = "((i.todo s.no) or i.later) o.state",
expectedQueryString = "(i.todo s.none or i.later) o.state",
expectedQuerySortOrders = listOf(SortOrder.State())
expectedQuerySortOrders = listOf(SortOrder.State()),
expectedSqlSelection = "(((COALESCE(state, '') = ? AND scheduled_time_timestamp IS NULL) OR COALESCE(state, '') = ?))",
expectedSelectionArgs = listOf("TODO", "LATER")
),
Parameter(
queryString = "o.title",
Expand All @@ -292,7 +294,12 @@ class QueryTest(private val param: Parameter) : OrgzlyTest() {
expectedSelectionArgs = listOf(),
expectedSqlOrder = "title, lft",
expectedQuerySortOrders = listOf(SortOrder.Title())
)
),
Parameter(
queryString = "s.no",
expectedQueryString = "s.none",
expectedSqlSelection = "(scheduled_time_timestamp IS NULL)"
),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.orgzly.android.util

import android.os.Environment
import android.text.style.URLSpan
import com.orgzly.android.ui.views.style.FileLinkSpan
import com.orgzly.android.ui.views.style.IdLinkSpan
import org.hamcrest.CoreMatchers.equalTo
import org.junit.After
import org.junit.Assert.assertThat
import org.junit.Before
import org.junit.Test
Expand All @@ -18,70 +18,99 @@ class OrgFormatterLinkTest(private val param: Parameter) : OrgFormatterTest() {

data class Span(val start: Int, val end: Int, val klass: Class<*>)

data class Parameter(val input: String, val output: String, val startEnd: List<Span>)
data class Parameter(
val inputString: String,
val outputString: String,
val expectedSpans: List<Span>)

@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()

File(Environment.getExternalStorageDirectory(), "orgzly-tests").let { dir ->
File(context.cacheDir, "orgzly-tests").let { dir ->
if (!dir.exists() && !dir.mkdirs()) {
throw IOException("Failed to create $dir")
}

MiscUtils.writeStringToFile("Lorem ipsum", File(dir, "document.txt"))

val classLoader = javaClass.classLoader
?: throw IOException("Failed to get a class loader for $javaClass")
?: throw IOException("Failed to get a class loader for $javaClass")

classLoader.getResourceAsStream("assets/images/logo.png").use { stream ->
MiscUtils.writeStreamToFile(stream, File(dir, "logo.png"))
}
}
}

@After
override fun tearDown() {
super.tearDown()

File(context.cacheDir, "orgzly-tests").let { dir ->
dir.deleteRecursively()
}
}

companion object {
@JvmStatic @Parameterized.Parameters(name = "{index}: {0}")
fun data(): Collection<Parameter> {
return listOf(
Parameter("[[orgzly-tests/document.txt]]", "orgzly-tests/document.txt", listOf(Span(0, 25, FileLinkSpan::class.java))),
Parameter("[[./document.txt]]", "./document.txt", listOf(Span(0, 14, FileLinkSpan::class.java))),
Parameter("[[/document.txt]]", "/document.txt", listOf(Span(0, 13, FileLinkSpan::class.java))),
Parameter("[[document.txt]]", "document.txt", listOf(Span(0, 12, FileLinkSpan::class.java))),
Parameter("[[orgzly-tests/document.txt]]", "orgzly-tests/document.txt", listOf(Span(0, 25, FileLinkSpan::class.java))),
Parameter("[[./document.txt]]", "./document.txt", listOf(Span(0, 14, FileLinkSpan::class.java))),
Parameter("[[/document.txt]]", "/document.txt", listOf(Span(0, 13, FileLinkSpan::class.java))),
Parameter("[[document.txt]]", "document.txt", listOf(Span(0, 12, FileLinkSpan::class.java))),

Parameter("file:orgzly-tests/document.txt", "file:orgzly-tests/document.txt", listOf(Span(0, 30, FileLinkSpan::class.java))),
Parameter("[[file:orgzly-tests/document.txt]]", "file:orgzly-tests/document.txt", listOf(Span(0, 30, FileLinkSpan::class.java))),
Parameter("[[file:orgzly-tests/document.txt][Document]]", "Document", listOf(Span(0, 8, FileLinkSpan::class.java))),

Parameter("file:orgzly-tests/document.txt", "file:orgzly-tests/document.txt", listOf(Span(0, 30, FileLinkSpan::class.java))),
Parameter("[[file:orgzly-tests/document.txt]]", "file:orgzly-tests/document.txt", listOf(Span(0, 30, FileLinkSpan::class.java))),
Parameter("[[file:orgzly-tests/document.txt][Document]]", "Document", listOf(Span(0, 8, FileLinkSpan::class.java))),
Parameter("id:45DFE015-255E-4B86-B957-F7FD77364DCA", "id:45DFE015-255E-4B86-B957-F7FD77364DCA", listOf(Span(0, 39, IdLinkSpan::class.java))),
Parameter("[[id:45DFE015-255E-4B86-B957-F7FD77364DCA]]", "id:45DFE015-255E-4B86-B957-F7FD77364DCA", listOf(Span(0, 39, IdLinkSpan::class.java))),
Parameter("id:foo", "id:foo", listOf(Span(0, 6, IdLinkSpan::class.java))),
Parameter("[[id:foo]]", "id:foo", listOf(Span(0, 6, IdLinkSpan::class.java))),

Parameter("id:45DFE015-255E-4B86-B957-F7FD77364DCA", "id:45DFE015-255E-4B86-B957-F7FD77364DCA", listOf(Span(0, 39, IdLinkSpan::class.java))),
Parameter("[[id:45DFE015-255E-4B86-B957-F7FD77364DCA]]", "id:45DFE015-255E-4B86-B957-F7FD77364DCA", listOf(Span(0, 39, IdLinkSpan::class.java))),
Parameter("id:foo", "id:foo", listOf(Span(0, 6, IdLinkSpan::class.java))),
Parameter("[[id:foo]]", "id:foo", listOf(Span(0, 6, IdLinkSpan::class.java))),
Parameter("mailto:[email protected]", "mailto:[email protected]", listOf(Span(0, 14, URLSpan::class.java))),
Parameter("[[mailto:[email protected]]]", "mailto:[email protected]", listOf(Span(0, 14, URLSpan::class.java))),

Parameter("mailto:[email protected]", "mailto:[email protected]", listOf(Span(0, 14, URLSpan::class.java))),
Parameter("[[mailto:[email protected]]]", "mailto:[email protected]", listOf(Span(0, 14, URLSpan::class.java))),
Parameter("[[id:123][[a] b]]", "[a] b", listOf(Span(0, 5, IdLinkSpan::class.java))),
Parameter("[[id:123][[a] b]] [[./456][[c] d]]", "[a] b [c] d", listOf(Span(0, 5, IdLinkSpan::class.java), Span(6, 11, FileLinkSpan::class.java))),

Parameter("[[id:123][[a] b]]", "[a] b", listOf(Span(0, 5, IdLinkSpan::class.java))),
Parameter("[[id:123][[a] b]] [[./456][[c] d]]", "[a] b [c] d", listOf(Span(0, 5, IdLinkSpan::class.java), Span(6, 11, FileLinkSpan::class.java))),
Parameter("[[gnus:msgid][subject]]", "subject", listOf(Span(0, 7, FileLinkSpan::class.java))),
Parameter("[[gnus:\\[Gmail\\]/All Mail#msgid][subject]]", "subject", listOf(Span(0, 7, FileLinkSpan::class.java))),

Parameter("[[gnus:msgid][subject]]", "subject", listOf(Span(0, 7, FileLinkSpan::class.java))),
Parameter("[[gnus:\\[Gmail\\]/All Mail#msgid][subject]]", "subject", listOf(Span(0, 7, FileLinkSpan::class.java)))
Parameter("[[id:a][b]] [[id:1][2]]", "b 2", listOf(Span(0, 1, IdLinkSpan::class.java), Span(2, 3, IdLinkSpan::class.java))),
Parameter("[[id:a][b]][[id:1][2]]", "b2", listOf(Span(0, 1, IdLinkSpan::class.java), Span(1, 2, IdLinkSpan::class.java))),

// Do not linkify
Parameter("strhttp://orgzly.com/", "strhttp://orgzly.com/", emptyList()),
Parameter("Need activity with <action android:name=\"android.intent.action.VIEW\"/>", "Need activity with <action android:name=\"android.intent.action.VIEW\"/>", emptyList())
)
}
}

@Test
fun testLink() {
val spannable = OrgSpannable(param.input)
val parseResult = ParseResult(param.inputString)

val msg = "${param.inputString} -> ${parseResult.outputString}"

assertThat(
"Number of spans found is different then expected: $msg",
parseResult.foundSpans.size,
equalTo(param.expectedSpans.size))

assertThat(parseResult.outputString, equalTo(param.outputString))

assertThat(spannable.string, equalTo(param.output))
assertThat(spannable.spans.size, equalTo(param.startEnd.size))
for (i in parseResult.foundSpans.indices) {
assertThat(parseResult.foundSpans[i].start, equalTo(param.expectedSpans[i].start))
assertThat(parseResult.foundSpans[i].end, equalTo(param.expectedSpans[i].end))

for (i in spannable.spans.indices) {
assertThat(spannable.spans[i].start, equalTo(param.startEnd[i].start))
assertThat(spannable.spans[i].end, equalTo(param.startEnd[i].end))
assertThat(spannable.spans[i].span.javaClass.simpleName, equalTo(param.startEnd[i].klass.simpleName))
assertThat(
"Found span class is different then expected: $msg",
parseResult.foundSpans[i].span.javaClass.simpleName,
equalTo(param.expectedSpans[i].klass.simpleName))
}
}
}
Loading

0 comments on commit 1a9225e

Please sign in to comment.