Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class ExternalLinksTest(private val param: Parameter) : OrgzlyTest() {
onBook(0).perform(click())

// Click on link
onNoteInBook(1, R.id.item_head_content).perform(clickClickableSpan(param.link))
onNoteInBook(1, R.id.note_content_section_text).perform(clickClickableSpan(param.link))

param.check()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,36 +66,36 @@ class InternalLinksTest : OrgzlyTest() {

@Test
fun testDifferentCaseUuidInternalLink() {
onNoteInBook(1, R.id.item_head_content)
onNoteInBook(1, R.id.note_content_section_text)
.perform(clickClickableSpan("id:bdce923b-C3CD-41ED-B58E-8BDF8BABA54F"))
onView(withId(R.id.fragment_note_title)).check(matches(withText("Note [b-2]")))
}

@Test
fun testDifferentCaseCustomIdInternalLink() {
onNoteInBook(2, R.id.item_head_content)
onNoteInBook(2, R.id.note_content_section_text)
.perform(clickClickableSpan("#Different case custom id"))
onView(withId(R.id.fragment_note_title)).check(matches(withText("Note [b-1]")))
}

@Test
fun testCustomIdLink() {
onNoteInBook(3, R.id.item_head_content)
onNoteInBook(3, R.id.note_content_section_text)
.perform(clickClickableSpan("#Link to note in a different book"))
onView(withId(R.id.fragment_note_title)).check(matches(withText("Note [b-3]")))
}

@Test
fun testBookLink() {
onNoteInBook(4, R.id.item_head_content)
onNoteInBook(4, R.id.note_content_section_text)
.perform(clickClickableSpan("file:book-b.org"))
onView(withId(R.id.fragment_book_view_flipper)).check(matches(isDisplayed()))
onNoteInBook(1, R.id.item_head_title).check(matches(withText("Note [b-1]")))
}

@Test
fun testBookRelativeLink() {
onNoteInBook(5, R.id.item_head_content)
onNoteInBook(5, R.id.note_content_section_text)
.perform(clickClickableSpan("file:./book-b.org"))
onView(withId(R.id.fragment_book_view_flipper)).check(matches(isDisplayed()))
onNoteInBook(1, R.id.item_head_title).check(matches(withText("Note [b-1]")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ public void testContentOfFoldedNoteDisplayed() {
onView(withId(R.id.fragment_query_search_view_flipper)).check(matches(isDisplayed()));
onNotesInSearch().check(matches(recyclerViewItemCount(3)));
onNoteInSearch(1, R.id.item_head_title).check(matches(allOf(withText(containsString("Note B")), isDisplayed())));
onNoteInSearch(1, R.id.item_head_content).check(matches(allOf(withText(containsString("Content for Note B")), isDisplayed())));
onNoteInSearch(1, R.id.note_content_section_text).check(matches(allOf(withText(containsString("Content for Note B")), isDisplayed())));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void testChangeDefaultPriorityAgendaResultsShouldBeReordered() {
public void testDisplayedContentInBook() {
onBook(0).perform(click());

onNoteInBook(1, R.id.item_head_content)
onNoteInBook(1, R.id.note_content_section_text)
.check(matches(allOf(withText(containsString("Content for [a-1]")), isDisplayed())));

onActionItemClick(R.id.activity_action_settings, R.string.settings);
Expand All @@ -91,7 +91,7 @@ public void testDisplayedContentInBook() {
pressBack();
pressBack();

onNoteInBook(1, R.id.item_head_content).check(matches(not(isDisplayed())));
onNoteInBook(1, R.id.item_head_content_list).check(matches(not(isDisplayed())));
}

private void setDefaultPriority(String priority) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package com.orgzly.android.ui.notes

import org.hamcrest.Matchers.emptyCollectionOf
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThat
import org.junit.Test
import java.util.Random

// TODO - check CRLF vs LF vs whatever MacOS does
class NoteContentTest {

@Test
fun emptyString() {
val parse = NoteContent.parse("")
assertThat(parse, (emptyCollectionOf(NoteContent.javaClass)))
}

@Test
fun emptyLinesShouldStayInSingleSection() {
checkExpected("\n\n", listOf(NoteContent("\n\n", 0, 1, NoteContent.TextType.TEXT)))
}

@Test
fun pipeInText() {
checkExpected("""foo
|

foo|bar""", listOf(
NoteContent("foo\n", 0, 3, NoteContent.TextType.TEXT),
NoteContent("|\n", 4, 5, NoteContent.TextType.TABLE),
NoteContent("\nfoo|bar", 6, 13, NoteContent.TextType.TEXT)
))
}

@Test
fun singleTable() {
checkExpected("""|a|b|
|c|d|
""", listOf(NoteContent("""|a|b|
|c|d|
""", 0, 11, NoteContent.TextType.TABLE)))
}

@Test
fun singleTableNoFinalNewline() {
checkExpected("""|a|b|
|c|d|""", listOf(NoteContent("""|a|b|
|c|d|""", 0, 10, NoteContent.TextType.TABLE)))
}

@Test
fun singleLineTextTableText() {
checkExpected("""foo
|
bar""", listOf(
NoteContent("foo\n", 0, 3, NoteContent.TextType.TEXT),
NoteContent("|\n", 4, 5, NoteContent.TextType.TABLE),
NoteContent("bar", 6, 8, NoteContent.TextType.TEXT)
))
}


@Test
fun blankLineTextTableText() {
checkExpected("""
|
bar
""", listOf(
NoteContent("\n", 0, 0, NoteContent.TextType.TEXT),
NoteContent("|\n", 1, 2, NoteContent.TextType.TABLE),
NoteContent("bar\n", 3, 6, NoteContent.TextType.TEXT)
))
}

@Test
fun tableBlankLineTable() {
checkExpected("""|zoo|

|zog|""", listOf(
NoteContent("|zoo|\n", 0, 5, NoteContent.TextType.TABLE),
NoteContent("\n", 6, 6, NoteContent.TextType.TEXT),
NoteContent("|zog|", 7, 11, NoteContent.TextType.TABLE)
))
}

@Test
fun textTableBlankLineText() {
checkExpected("""foo
|

chops""", listOf(
NoteContent("foo\n", 0, 3, NoteContent.TextType.TEXT),
NoteContent("|\n", 4, 5, NoteContent.TextType.TABLE),
NoteContent("\nchops", 6, 11, NoteContent.TextType.TEXT)
))
}


@Test
fun textTableTextTableText() {
checkExpected("""text1
|table2a|
|table2b|
text3a
text3b
text3c
|table4|
text5
""", listOf(
NoteContent("text1\n", 0, 5, NoteContent.TextType.TEXT),
NoteContent("|table2a|\n|table2b|\n", 6, 25, NoteContent.TextType.TABLE),
NoteContent("text3a\ntext3b\ntext3c\n", 26, 46, NoteContent.TextType.TEXT),
NoteContent("|table4|\n", 47, 55, NoteContent.TextType.TABLE),
NoteContent("text5\n", 56, 61, NoteContent.TextType.TEXT)
))
}

@Test
fun randomStringsRoundTrip() {

val stringAtoms: List<String> = listOf("\n", "a", "|")

for (i in 0..1000) {
val rawStringLength = Random().nextInt(100)
val builder = StringBuilder()
for (j in 0..rawStringLength) {
builder.append(stringAtoms.random())
}

val raw = builder.toString()

val actual: List<NoteContent> = NoteContent.parse(raw)

val roundTripped: String = actual.fold("") { acc: String, current: NoteContent -> acc + current.text }

assertEquals(raw, roundTripped)

}

}


private fun checkExpected(input: String, expected: List<NoteContent>) {
val actual: List<NoteContent> = NoteContent.parse(input)
assertEquals(expected, actual)

val roundTripped: String = actual.fold("") { acc: String, current: NoteContent -> acc + current.text }

assertEquals(input, roundTripped)

actual.forEach {
assertEquals(it.text, input.substring(it.startOffset, it.endOffset + 1))
}
}
}
3 changes: 3 additions & 0 deletions app/src/main/java/com/orgzly/android/AppIntent.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class AppIntent {
public static final String ACTION_OPEN_BOOKS = "com.orgzly.intent.action.OPEN_BOOKS";
public static final String ACTION_OPEN_BOOK = "com.orgzly.intent.action.OPEN_BOOK";
public static final String ACTION_OPEN_SETTINGS = "com.orgzly.intent.action.OPEN_SETTINGS";
public static final String ACTION_EDIT_TABLE = "com.orgzly.intent.action.EDIT_TABLE";

public static final String ACTION_SHOW_SNACKBAR = "com.orgzly.intent.action.SHOW_SNACKBAR";

Expand All @@ -40,6 +41,8 @@ public class AppIntent {
public static final String EXTRA_BOOK_PREFACE = "com.orgzly.intent.extra.BOOK_PREFACE";
public static final String EXTRA_NOTE_ID = "com.orgzly.intent.extra.NOTE_ID";
public static final String EXTRA_NOTE_CONTENT = "com.orgzly.intent.extra.NOTE_CONTENT";
public static final String EXTRA_TABLE_START_OFFSET = "com.orgzly.intent.action.EXTRA_TABLE_START_OFFSET";
public static final String EXTRA_TABLE_END_OFFSET = "com.orgzly.intent.action.EXTRA_TABLE_END_OFFSET";
public static final String EXTRA_QUERY_STRING = "com.orgzly.intent.extra.QUERY_STRING";
public static final String EXTRA_PROPERTY_NAME = "com.orgzly.intent.extra.PROPERTY_NAME";
public static final String EXTRA_PROPERTY_VALUE = "com.orgzly.intent.extra.PROPERTY_VALUE";
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/orgzly/android/di/AppComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.orgzly.android.ui.BookChooserActivity
import com.orgzly.android.ui.TemplateChooserActivity
import com.orgzly.android.ui.books.BooksFragment
import com.orgzly.android.ui.main.MainActivity
import com.orgzly.android.ui.note.EditTableFragment
import com.orgzly.android.ui.note.NoteFragment
import com.orgzly.android.ui.notes.NotesFragment
import com.orgzly.android.ui.notes.book.BookFragment
Expand Down Expand Up @@ -68,6 +69,7 @@ interface AppComponent {
fun inject(arg: SearchFragment)
fun inject(arg: AgendaFragment)
fun inject(arg: NoteFragment)
fun inject(arg: EditTableFragment)
fun inject(arg: SavedSearchesFragment)
fun inject(arg: SavedSearchFragment)
fun inject(arg: RefileFragment)
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/com/orgzly/android/ui/DisplayManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.orgzly.android.query.Query;
import com.orgzly.android.query.QueryParser;
import com.orgzly.android.query.user.InternalQueryParser;
import com.orgzly.android.ui.note.EditTableFragment;
import com.orgzly.android.ui.savedsearch.SavedSearchFragment;
import com.orgzly.android.ui.main.MainActivity;
import com.orgzly.android.ui.notes.book.BookFragment;
Expand Down Expand Up @@ -151,6 +152,16 @@ public static void displayExistingNote(FragmentManager fragmentManager, long boo
}
}

public static void displayEditTable(FragmentManager fragmentManager,
long bookId,
long noteId,
int tableStartOffset,
int tableEndOffset) {
Fragment fragment = EditTableFragment.newInstance(bookId, noteId, tableStartOffset, tableEndOffset);

displayNoteFragment(fragmentManager, fragment);
}

public static void displayNewNote(FragmentManager fragmentManager, NotePlace target) {
Fragment fragment = NoteFragment.forNewNote(target);

Expand Down
30 changes: 28 additions & 2 deletions app/src/main/java/com/orgzly/android/ui/main/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@
import com.orgzly.android.usecase.SavedSearchCreate;
import com.orgzly.android.usecase.SavedSearchDelete;
import com.orgzly.android.usecase.SavedSearchExport;
import com.orgzly.android.usecase.SavedSearchImport;
import com.orgzly.android.usecase.SavedSearchMoveDown;
import com.orgzly.android.usecase.SavedSearchMoveUp;
import com.orgzly.android.usecase.SavedSearchUpdate;
Expand All @@ -101,7 +100,6 @@
import com.orgzly.android.usecase.UseCaseRunner;
import com.orgzly.android.util.AppPermissions;
import com.orgzly.android.util.LogUtils;
import com.orgzly.android.util.MiscUtils;
import com.orgzly.org.datetime.OrgDateTime;

import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -635,6 +633,7 @@ protected void onResumeFragments() {

LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.registerReceiver(receiver, new IntentFilter(AppIntent.ACTION_OPEN_NOTE));
bm.registerReceiver(receiver, new IntentFilter(AppIntent.ACTION_EDIT_TABLE));
bm.registerReceiver(receiver, new IntentFilter(AppIntent.ACTION_FOLLOW_LINK_TO_NOTE_WITH_PROPERTY));
bm.registerReceiver(receiver, new IntentFilter(AppIntent.ACTION_FOLLOW_LINK_TO_FILE));
bm.registerReceiver(receiver, new IntentFilter(AppIntent.ACTION_OPEN_SAVED_SEARCHES));
Expand Down Expand Up @@ -1267,6 +1266,15 @@ public void onNoteOpen(long noteId) {
viewModel.openNote(noteId);
}

public void editTableOfView(View view) {
editTable(
(long) view.getTag(AppIntent.EXTRA_BOOK_ID.hashCode()),
(long) view.getTag(AppIntent.EXTRA_NOTE_ID.hashCode()),
(int) view.getTag(AppIntent.EXTRA_TABLE_START_OFFSET.hashCode()),
(int) view.getTag(AppIntent.EXTRA_TABLE_END_OFFSET.hashCode())
);
}

// TODO: Consider creating NavigationBroadcastReceiver
public static void openSpecificNote(long bookId, long noteId) {
Intent intent = new Intent(AppIntent.ACTION_OPEN_NOTE);
Expand All @@ -1275,6 +1283,15 @@ public static void openSpecificNote(long bookId, long noteId) {
LocalBroadcastManager.getInstance(App.getAppContext()).sendBroadcast(intent);
}

public static void editTable(long bookId, long noteId, int tableStartOffset, int tableEndOffset) {
Intent intent = new Intent(AppIntent.ACTION_EDIT_TABLE);
intent.putExtra(AppIntent.EXTRA_NOTE_ID, noteId);
intent.putExtra(AppIntent.EXTRA_BOOK_ID, bookId);
intent.putExtra(AppIntent.EXTRA_TABLE_START_OFFSET, tableStartOffset);
intent.putExtra(AppIntent.EXTRA_TABLE_END_OFFSET, tableEndOffset);
LocalBroadcastManager.getInstance(App.getAppContext()).sendBroadcast(intent);
}

public static void followLinkToFile(String path) {
Intent intent = new Intent(AppIntent.ACTION_FOLLOW_LINK_TO_FILE);
intent.putExtra(AppIntent.EXTRA_PATH, path);
Expand Down Expand Up @@ -1307,6 +1324,15 @@ private void handleIntent(@NonNull Intent intent, @NonNull String action) {
break;
}

case AppIntent.ACTION_EDIT_TABLE: {
long bookId = intent.getLongExtra(AppIntent.EXTRA_BOOK_ID, -1);
long noteId = intent.getLongExtra(AppIntent.EXTRA_NOTE_ID, -1);
int tableStartOffset = intent.getIntExtra(AppIntent.EXTRA_TABLE_START_OFFSET, -1);
int tableEndOffset = intent.getIntExtra(AppIntent.EXTRA_TABLE_END_OFFSET, -1);
DisplayManager.displayEditTable(getSupportFragmentManager(), bookId, noteId, tableStartOffset, tableEndOffset);
break;
}

case AppIntent.ACTION_OPEN_SAVED_SEARCHES: {
DisplayManager.displaySavedSearches(getSupportFragmentManager());
break;
Expand Down
Loading