Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0b6bf61
Move to Material 3 with real night resources (#524)
andiwand Jul 28, 2026
1b73415
Replace the landing copy with the recently opened documents (#525)
andiwand Jul 28, 2026
29ebda2
Open the system picker directly (#526)
andiwand Jul 28, 2026
ad75abd
Browse the folders you have granted access to (#527)
andiwand Jul 28, 2026
f5bf3eb
Offer the folder browser only for the ooxml types we open
andiwand Jul 28, 2026
7f092ea
Keep the settings on screen while there is nothing to list
andiwand Jul 28, 2026
89fcd31
Swipe a recent document away, and say when it was opened (#528)
andiwand Jul 28, 2026
8df9a17
Drop the open action from the toolbar (#529)
andiwand Jul 28, 2026
2996064
Let the row say it is a recent, instead of guessing from the subtitle
andiwand Jul 28, 2026
63c7068
Cap the recents list when an undo puts a document back
andiwand Jul 28, 2026
0b720cb
Offer the ad removal from the settings section (#530)
andiwand Jul 28, 2026
a0a6e1f
Put the document actions where the thumb is (#531)
andiwand Jul 28, 2026
fc10c72
Take the empty toolbar off the screen (#542)
andiwand Jul 28, 2026
c340291
Open every format the core renders, not just half of them (#546)
andiwand Jul 28, 2026
69d45bb
Close the three gaps the review found
andiwand Jul 28, 2026
2ad786c
Take out what the redesign left behind
andiwand Jul 28, 2026
d8ce816
Say which folder you are in, and remove a recent one way
andiwand Jul 28, 2026
a4a7f93
Scroll to the setting the test is looking for
andiwand Jul 28, 2026
190a357
Shorten CLAUDE.md to the things it is needed for
andiwand Jul 28, 2026
aad3680
Close the keyboard before clicking what it is covering
andiwand Jul 28, 2026
46d34b9
Swipe a folder away too, and stop asking first
andiwand Jul 28, 2026
0a53625
Delete the strings whose features are gone
andiwand Jul 28, 2026
fd15a10
Keep the open button on screen while the list is empty
andiwand Jul 28, 2026
0b9cab2
Lift the document buttons off the bottom of the screen
andiwand Jul 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
311 changes: 150 additions & 161 deletions CLAUDE.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,19 @@ dependencies {
implementation libs.androidx.core
implementation libs.material
implementation libs.androidx.webkit
implementation libs.androidx.recyclerview
implementation libs.androidx.lifecycle.viewmodel
implementation libs.androidx.lifecycle.livedata

implementation libs.asset.extractor

testImplementation libs.junit

androidTestImplementation libs.espresso.core
androidTestImplementation libs.espresso.intents
// RecyclerViewActions: the landing screen is one list, and what a test wants to reach
// is regularly a row that has not been bound yet on a small screen
androidTestImplementation libs.espresso.contrib
androidTestImplementation libs.androidx.test.rules
androidTestImplementation libs.androidx.test.runner
androidTestImplementation libs.androidx.test.junit
Expand Down
Binary file added app/src/androidTest/assets/11KB.doc
Binary file not shown.
Binary file not shown.
Binary file added app/src/androidTest/assets/style-various-1.ppt
Binary file not shown.
Binary file added app/src/androidTest/assets/style-various-1.pptx
Binary file not shown.
110 changes: 109 additions & 1 deletion app/src/androidTest/java/app/opendocument/droid/test/CoreTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class CoreTest {
private var passwordTestFile: File? = null
private var spreadsheetTestFile: File? = null
private var docxTestFile: File? = null
private var pptxTestFile: File? = null
private var docTestFile: File? = null
private var pptTestFile: File? = null
private var xlsTestFile: File? = null

private val coreLoader: CoreLoader
get() = checkNotNull(sharedLoader) { "the core loader was not started" }
Expand Down Expand Up @@ -58,6 +62,22 @@ class CoreTest {
assetManager.open("style-various-1.docx"),
File(appCtx.cacheDir, "style-various-1.docx"),
)
pptxTestFile =
extract(
assetManager.open("style-various-1.pptx"),
File(appCtx.cacheDir, "style-various-1.pptx"),
)
docTestFile = extract(assetManager.open("11KB.doc"), File(appCtx.cacheDir, "11KB.doc"))
pptTestFile =
extract(
assetManager.open("style-various-1.ppt"),
File(appCtx.cacheDir, "style-various-1.ppt"),
)
xlsTestFile =
extract(
assetManager.open("file_example_XLS_10.xls"),
File(appCtx.cacheDir, "file_example_XLS_10.xls"),
)
}

@After
Expand All @@ -66,6 +86,10 @@ class CoreTest {
passwordTestFile?.delete()
spreadsheetTestFile?.delete()
docxTestFile?.delete()
pptxTestFile?.delete()
docTestFile?.delete()
pptTestFile?.delete()
xlsTestFile?.delete()
}

@Test
Expand Down Expand Up @@ -109,6 +133,90 @@ class CoreTest {
Assert.assertTrue("the edited document should have been saved", result.isFile)
}

/**
* The formats that used to be sent off for conversion instead: presentations, and the legacy
* binary microsoft ones. The core renders all four, so the app hands them to it.
*/
@Test
fun testPptx() {
val views =
coreLoader.host(
prefix = "pptx-test",
inputPath = requireFile(pptxTestFile).absolutePath,
cachePath = File(cacheDir(), "pptx_cache").path,
)
Assert.assertFalse("hosting the PPTX file should produce a view", views.isEmpty())
}

@Test
fun testDoc() {
val views =
coreLoader.host(
prefix = "doc-test",
inputPath = requireFile(docTestFile).absolutePath,
cachePath = File(cacheDir(), "doc_cache").path,
)
Assert.assertFalse("hosting the DOC file should produce a view", views.isEmpty())
}

@Test
fun testPpt() {
val views =
coreLoader.host(
prefix = "ppt-test",
inputPath = requireFile(pptTestFile).absolutePath,
cachePath = File(cacheDir(), "ppt_cache").path,
)
Assert.assertFalse("hosting the PPT file should produce a view", views.isEmpty())
}

@Test
fun testXls() {
val views =
coreLoader.host(
prefix = "xls-test",
inputPath = requireFile(xlsTestFile).absolutePath,
cachePath = File(cacheDir(), "xls_cache").path,
)
Assert.assertFalse("hosting the XLS file should produce a view", views.isEmpty())
}

/**
* Which of the formats the core renders it can also write back again - the answer
* `DocumentFragment` puts the Edit button up by. Offering it for a document the core will not
* save only gets as far as a failed save, which is what happened to the legacy binary formats
* when they started going through the core.
*/
@Test
fun testEditableFormats() {
assertEditable("odt-editable", requireFile(testFile), true)
assertEditable("docx-editable", requireFile(docxTestFile), true)

// the core declares these read only: the three legacy binary formats, ooxml presentations
// and every spreadsheet - the last being issue #442, which the core has its own TODO for
assertEditable("doc-editable", requireFile(docTestFile), false)
assertEditable("ppt-editable", requireFile(pptTestFile), false)
assertEditable("xls-editable", requireFile(xlsTestFile), false)
assertEditable("pptx-editable", requireFile(pptxTestFile), false)
assertEditable("ods-editable", requireFile(spreadsheetTestFile), false)
}

private fun assertEditable(prefix: String, file: File, expected: Boolean) {
coreLoader.host(
prefix = prefix,
inputPath = file.absolutePath,
cachePath = File(cacheDir(), prefix).path,
editable = true,
keepDocument = true,
)

Assert.assertEquals(
"the core should report ${file.name} as ${if (expected) "editable" else "read only"}",
expected,
coreLoader.isDocumentEditable,
)
}

@Test
fun testPasswordProtectedDocumentWithoutPassword() {
Assert.assertThrows(OdrException.FileEncrypted::class.java) {
Expand Down Expand Up @@ -176,7 +284,7 @@ class CoreTest {
// set of statics. nothing here goes through loadAsync, so both handlers can be the main
// looper and the listener is never called back
val handler = Handler(Looper.getMainLooper())
val loader = CoreLoader(appCtx, true)
val loader = CoreLoader(appCtx)
sharedLoader = loader
loader.initialize(
object : FileLoader.FileLoaderListener {
Expand Down
Loading
Loading