From a0080967a484bf42a23e7e7f730cbb171059c603 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 21 Aug 2026 17:04:41 +0200 Subject: [PATCH 1/3] Open what the core can read, and say when it cannot A zip file opens and lists what is inside, and tapping an entry shows it. Photos and text files the reader used to refuse open too. The reader now asks the core what it can read rather than keeping a list of its own, which had gone out of date. A file that will not open says so, and offers to write to us when something went wrong on our side. Music and films are no longer offered. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AHynmW7Vk9bXvUFxLkwu6W --- CHANGELOG.md | 13 + OpenDocumentReader/Constants.swift | 4 + OpenDocumentReader/CoreWrapper.swift | 41 ++- OpenDocumentReader/Document.swift | 4 + .../DocumentViewController.swift | 290 ++++++++++++++---- .../ca.lproj/Localizable.strings | 12 + .../cs.lproj/Localizable.strings | 12 + .../da.lproj/Localizable.strings | 12 + .../de.lproj/Localizable.strings | 12 + .../en.lproj/Localizable.strings | 12 + .../es.lproj/Localizable.strings | 12 + .../fr.lproj/Localizable.strings | 12 + .../ga.lproj/Localizable.strings | 12 + .../it.lproj/Localizable.strings | 12 + .../ja.lproj/Localizable.strings | 12 + .../pl.lproj/Localizable.strings | 12 + .../pt-BR.lproj/Localizable.strings | 12 + .../ru.lproj/Localizable.strings | 12 + .../sl.lproj/Localizable.strings | 12 + .../tr.lproj/Localizable.strings | 12 + .../zh-Hans.lproj/Localizable.strings | 12 + .../ArchiveDocumentTests.swift | 263 ++++++++++++++++ .../FailedToOpenTests.swift | 91 ++++++ .../LockedDocumentTests.swift | 40 ++- .../OpenDocumentReaderTests.swift | 34 +- OpenDocumentReaderTests/test.epub | Bin 0 -> 369 bytes OpenDocumentReaderTests/test.pages | Bin 0 -> 369 bytes OpenDocumentReaderTests/test.zip | Bin 0 -> 369 bytes configs/full/Info.plist | 4 +- configs/lite/Info.plist | 4 +- scripts/make-test-fixtures.py | 15 + 31 files changed, 906 insertions(+), 89 deletions(-) create mode 100644 OpenDocumentReaderTests/ArchiveDocumentTests.swift create mode 100644 OpenDocumentReaderTests/FailedToOpenTests.swift create mode 100644 OpenDocumentReaderTests/test.epub create mode 100644 OpenDocumentReaderTests/test.pages create mode 100644 OpenDocumentReaderTests/test.zip diff --git a/CHANGELOG.md b/CHANGELOG.md index 5909337..aa2a167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,19 @@ open: **a second build under the same version goes under the already cut heading, not back under `Unreleased`.** Date the heading and add its compare link once the version tag exists. +## [Unreleased] + +### Added + +- A zip file opens and lists what is inside. Tapping an entry shows it. +- Photos and text files the reader used to refuse now open. + +### Changed + +- A file that will not open says so, and offers to write to us when something + went wrong on our side. +- The app no longer offers itself for music and films. + ## [1.42] ### Added diff --git a/OpenDocumentReader/Constants.swift b/OpenDocumentReader/Constants.swift index 6a556ce..f0d6364 100644 --- a/OpenDocumentReader/Constants.swift +++ b/OpenDocumentReader/Constants.swift @@ -12,6 +12,10 @@ enum Constants { /// Which of the house ad's rotations comes next. static let key_house_ad_index = "houseAdIndex" + /// Where a reader writes to when a file will not open. The same address the + /// message names, and the one OpenDocument.droid uses. + static let supportEmail = "support@opendocument.app" + /// ODR Pro on the App Store. This is the *paid* app: on iOS that is `at.tomtasche.reader`, /// while on Android the same bundle id names the free one. static let proAppStoreId = 1_452_061_743 diff --git a/OpenDocumentReader/CoreWrapper.swift b/OpenDocumentReader/CoreWrapper.swift index f59f59a..fb34ac5 100644 --- a/OpenDocumentReader/CoreWrapper.swift +++ b/OpenDocumentReader/CoreWrapper.swift @@ -77,14 +77,15 @@ private func selectViews(_ views: [HtmlView], _ documentType: DocumentType) -> [ } } -/// A csv is a *text* file to odrcore that also loads as a spreadsheet, so it -/// answers `isDocumentFile` with false and `asDocumentFile()` fails on it. -private func isCsv(_ file: DecodedFile) -> Bool { file.fileType == .commaSeparatedValues } - @objc final class CoreWrapper: NSObject { @objc private(set) var pageNames: [String] = [] @objc private(set) var pageURLs: [URL] = [] + /// Whether odrcore saw only a container and the page is a listing of what is + /// inside it. The reader asks because the system may know the same file as a + /// document of its own — see `systemKnowsItAsADocument`. + @objc private(set) var isArchive = false + /// Whether `backTranslate` has a document to apply an edit to. Only a /// document that said it takes one is kept, so having it *is* the answer. @objc var isEditable: Bool { lock.withLock { document != nil } } @@ -105,6 +106,7 @@ private func isCsv(_ file: DecodedFile) -> Bool { file.fileType == .commaSeparat pageNames = [] pageURLs = [] document = nil + isArchive = false let fileTypes = (try? DecodedFile.listFileTypes(path: inputPath)) ?? [] guard !fileTypes.isEmpty else { @@ -126,11 +128,22 @@ private func isCsv(_ file: DecodedFile) -> Bool { file.fileType == .commaSeparat } } - // odrcore also translates images, media and fonts, but only into an - // `` or a `