Skip to content

Add Quillpad import and fix Notally import#978

Merged
Crustack merged 5 commits into
mainfrom
feat/quillpad-import
Apr 12, 2026
Merged

Add Quillpad import and fix Notally import#978
Crustack merged 5 commits into
mainfrom
feat/quillpad-import

Conversation

@Crustack
Copy link
Copy Markdown
Owner

@Crustack Crustack commented Apr 12, 2026

Fixes #938
Closes #964

  • Adds importer for Quillpad
  • Fixes Notally Import (+ added import of Notally reminder to NotallyX reminders)
  • Added hint for Notally Import when using "Import from other App"

Summary by CodeRabbit

  • New Features

    • Added import support for Quillpad notes, allowing users to import existing notes from the Quillpad app.
  • Documentation

    • Updated README with import feature information for supported apps.
    • Added documentation page detailing the import workflow and supported sources.
  • Tests

    • Re-enabled and expanded import test suite with comprehensive Quillpad import validation.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 12, 2026

📝 Walkthrough

Walkthrough

This pull request adds import support for Quillpad and Notally applications alongside existing Google Keep and Evernote importers. Changes include: defining Quillpad backup data models, implementing ZIP extraction and JSON deserialization, introducing a Display interface to the ImportSource enum, extending import infrastructure utilities, updating the settings UI with a Notally info dialog, and adding comprehensive tests and documentation.

Changes

Cohort / File(s) Summary
Quillpad Import Implementation
app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadBackup.kt, app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt
New serializable data models for Quillpad backup structure (notes, notebooks, tags, reminders, attachments). QuillpadImporter implements ZIP extraction, JSON deserialization, markdown parsing, attachment categorization, and conversion to BaseNote format with progress tracking.
ImportSource Enhancement
app/src/main/java/com/philkes/notallyx/data/imports/NotesImporter.kt
Added Display interface for text and icon ID resolution. Extended ImportSource enum with QUILLPAD constant and corresponding interface implementations. Wired QUILLPAD to QuillpadImporter in dispatch logic.
Import Infrastructure
app/src/main/java/com/philkes/notallyx/data/model/Converters.kt, app/src/main/java/com/philkes/notallyx/utils/backup/ImportExtensions.kt
Promoted JSONObject extension functions from private to top-level. Enhanced import querying with dynamic column detection and fallback reminder parsing from legacy single-reminder columns.
Utility Extensions
app/src/main/java/com/philkes/notallyx/utils/IOExtensions.kt, app/src/main/java/com/philkes/notallyx/utils/NotallyUtils.kt, app/src/main/java/com/philkes/notallyx/utils/MiscExtensions.kt
Added file movement and MIME type detection. Introduced Notally reminder JSON parsing with frequency mapping to Repetition objects. Added Seconds type alias with millisecond conversion.
GoogleKeepImporter Refinement
app/src/main/java/com/philkes/notallyx/data/imports/google/GoogleKeepImporter.kt
Consolidated serialization API opt-in annotations at class level.
UI and View Updates
app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/settings/SettingsFragment.kt, app/src/main/java/com/philkes/notallyx/presentation/view/misc/TextWithIconAdapter.kt
Inserted Notally entry with info dialog at top of import source list using Display interface. Updated adapter to use immutable List type and Display methods for resolution.
Resources and Branding
app/src/main/res/drawable/icon_notally.xml, app/src/main/res/drawable/icon_quillpad.xml, app/src/main/res/values/strings.xml
New vector drawables for Notally and Quillpad. Added localized strings for import sources, error messages, and help text.
Documentation
README.md, documentation/docs/intro.md, documentation/docs/features/import-other-apps.mdx
Updated feature descriptions and added dedicated import feature documentation page listing all supported sources.
Tests
app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt, app/src/test/kotlin/com/philkes/notallyx/data/imports/quillpad/QuillpadImporterTest.kt
Reactivated NotesImporterTest with Quillpad case. Added comprehensive QuillpadImporterTest covering note conversion, folder mapping, attachments, and reminders.
Dependencies
app/build.gradle.kts
Updated Robolectric from 4.15.1 to 4.16.1.
Data Model Documentation
app/src/main/java/com/philkes/notallyx/data/model/Reminder.kt
Added KDoc comments for occurrence and dayOfWeek fields clarifying monthly repetition behavior.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as SettingsFragment
    participant Importer as QuillpadImporter
    participant ZIP as ZIP Handler
    participant JSON as JSON Parser
    participant Converter as Converter<br/>(toBaseNote)
    participant DB as Database/Storage

    User->>UI: Select "Quillpad" from import sources
    UI->>Importer: import(uri, destination, progress)
    Importer->>ZIP: Extract ZIP from contentResolver
    ZIP->>ZIP: Validate path traversal safety
    ZIP->>Importer: Extracted files + backup.json
    Importer->>JSON: Deserialize backup.json
    JSON->>Importer: QuillpadBackup object
    Importer->>Converter: Convert each note via toBaseNote()
    Converter->>Converter: Parse markdown, categorize attachments
    Converter->>Converter: Map notebooks & tags to labels
    Converter->>Importer: BaseNote objects
    Importer->>DB: Store notes & media files
    DB->>UI: Return import results
    UI->>User: Display completion
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related PRs

Poem

🐰 Hoppy news, dear notes take flight,
From Quillpad's ZIP and Notally's light,
New importers hop the storage way,
With markdown parsed and labels at play,
A burrow of features, cleaned up just right! ✨📝

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Quillpad import and fix Notally import' directly summarizes the main changes: adding Quillpad import functionality and fixing Notally import issues.
Linked Issues check ✅ Passed The PR successfully implements Quillpad import support (#964) and Notally import fixes (#938), including reminder conversion and import hint UI.
Out of Scope Changes check ✅ Passed All changes align with stated objectives: Quillpad importer, Notally import enhancements, helper utilities for imports, test coverage, documentation updates, and UI adjustments for import flow.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/quillpad-import

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

This was referenced Apr 12, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (5)
app/src/main/java/com/philkes/notallyx/utils/backup/ImportExtensions.kt (1)

69-90: Keep the projection explicit for required fields.

getOptionalColumns() currently returns whatever the source table happens to expose, but toBaseNote() still hard-requires a fixed core (id, type, folder, title, body, etc.). Starting from an explicit required projection and appending only truly optional columns would make unsupported schemas fail earlier and more predictably.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/philkes/notallyx/utils/backup/ImportExtensions.kt`
around lines 69 - 90, getOptionalColumns currently returns whatever columns
exist which can hide missing required fields; change it to start from an
explicit required projection (e.g., the fixed core fields used by toBaseNote
such as id, type, folder, title, body) and then append only truly optional
columns found in the DB; validate that all required columns are present and
throw or log a clear error if any required column (referenced by toBaseNote) is
missing, and keep your existing special-case for "body" using SUBSTR with
MAX_BODY_CHAR_LENGTH when building the final projection array in
getOptionalColumns.
app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt (1)

39-145: Add a Notally backup regression case to this suite.

This PR fixes Notally import behavior, but the runnable coverage here still only exercises Google Keep / Evernote / Quillpad. A Notally fixture is the regression that matters most now—especially for the new reminderreminders fallback in ImportExtensions.kt.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt`
around lines 39 - 145, Add a regression test for Notally by adding a new `@Test`
that calls testImport(ImportSource.NOTALLY, <expectedCount>) (or
testImport(prepareImportSources(ImportSource.NOTALLY), ImportSource.NOTALLY,
<expectedCount>)) and update prepareImportSources(importSource: ImportSource) to
handle ImportSource.NOTALLY returning the Notally fixture file name (e.g.,
"notally_export.zip" or your fixture name); ensure a corresponding Notally
fixture is present in the test resources so the NotesImporter code path (and the
ImportExtensions.kt reminder → reminders fallback) is exercised.
app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/settings/SettingsFragment.kt (1)

541-558: Avoid re-deriving the importer from the dialog index.

ImportSource.entries[which - 1] works only while the dialog order stays perfectly aligned with the enum declaration. A later insert/reorder will silently launch the wrong importer. It’s safer to keep a single list of chooser items and read the selected ImportSource? directly from that list.

♻️ One way to make the mapping explicit
-        val notallyItem =
-            mutableListOf(
-                object : Display {
-                    override fun getTextId(): Int {
-                        return R.string.notally
-                    }
-
-                    override fun getIconId(): Int {
-                        return R.drawable.icon_notally
-                    }
-                }
-            )
+        val chooserItems: List<Pair<Display, ImportSource?>> =
+            listOf(
+                object : Display {
+                    override fun getTextId(): Int = R.string.notally
+                    override fun getIconId(): Int = R.drawable.icon_notally
+                } to null
+            ) + ImportSource.entries.map { it to it }

         MaterialAlertDialogBuilder(requireContext())
             .setTitle(R.string.choose_other_app)
             .setAdapter(
                 TextWithIconAdapter(
                     requireContext(),
-                    notallyItem + ImportSource.entries.toMutableList(),
+                    chooserItems.map { it.first },
                     { item -> getString(item.getTextId()) },
                     Display::getIconId,
                 )
             ) { _, which ->
-                if (which == 0) {
+                val selected = chooserItems[which].second
+                if (selected == null) {
                     MaterialAlertDialogBuilder(requireContext())
                         .setMessage(
                             getString(
@@
-                selectedImportSource = ImportSource.entries[which - 1]
+                selectedImportSource = selected
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/settings/SettingsFragment.kt`
around lines 541 - 558, The code currently maps the dialog selection back to an
importer using ImportSource.entries[which - 1], which will break if enum order
or dialog list changes; instead build and reuse the actual chooser list used to
create the adapter (the list passed in alongside notallyItem and
Display::getIconId) — e.g., create a local val chooserList = notallyItem +
ImportSource.entries.toMutableList() and pass that to setAdapter, then set
selectedImportSource by reading chooserList[which] (or chooserList[which - 1] if
you keep the notallyItem header) so the selected value is taken directly from
the same list rather than re-deriving via ImportSource.entries. Ensure you
update the selection logic around selectedImportSource and the special-case
check for the notallyItem header to use the same chooserList indexing.
app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt (2)

77-80: Unused variables: noteReminders, noteTags, and tagMap.

These variables are computed but never used. The toBaseNote function accesses quillpadNote.tags and quillpadNote.reminders directly from the embedded note data instead. Either remove the unused variables or use them if the intent was to join data via IDs.

♻️ Remove unused variables
     val notebookMap = quillpadBackup.notebooks.associate { it.id to it.name }
-    val noteReminders = quillpadBackup.reminders.groupBy { it.noteId }
-    val noteTags = quillpadBackup.joins.groupBy { it.noteId }
-    val tagMap = quillpadBackup.tags.associate { it.id to it.name }

     val total = quillpadBackup.notes.size
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt`
around lines 77 - 80, Remove or use the unused variables noteReminders,
noteTags, and tagMap in QuillpadImporter.kt: either delete the lines that
compute noteReminders, noteTags, and tagMap (since toBaseNote reads
quillpadNote.tags and quillpadNote.reminders directly), or modify toBaseNote (or
its caller) to look up tags and reminders by noteId using noteTags,
noteReminders and resolve tag names via tagMap so those computed maps are
actually consumed; reference noteReminders, noteTags, tagMap and the toBaseNote
function when making the change.

43-48: Return type mismatch with interface.

The method returns Pair<List<BaseNote>, File> (non-null File), but the ExternalImporter interface declares Pair<List<BaseNote>, File?>. While this is type-safe (covariant), consider matching the interface signature exactly for consistency, or updating the interface if all importers always return a non-null File.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt`
around lines 43 - 48, The QuillpadImporter.import signature currently returns
Pair<List<BaseNote>, File> but the ExternalImporter interface declares
Pair<List<BaseNote>, File?>; update QuillpadImporter.import to return
Pair<List<BaseNote>, File?> (nullable File) to match the interface (or, if you
intentionally guarantee a non-null File across all importers, update the
ExternalImporter interface instead); adjust any usages of
QuillpadImporter.import or the returned pair to handle a nullable File, and
ensure the method implementation returns null where appropriate when no File is
produced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadBackup.kt`:
- Around line 3-14: The file unnecessarily uses the internal serialization
annotation; remove the import kotlinx.serialization.InternalSerializationApi and
delete all usages of `@InternalSerializationApi` on the data classes (e.g.,
QuillpadBackup and its related QuillpadNote, QuillpadNotebook, QuillpadTag,
QuillpadReminder, QuillpadJoin classes) so they rely only on `@Serializable` and
primitive/default properties remain unchanged; ensure only the
kotlinx.serialization.Serializable import remains and the classes compile
without the internal annotation.

In
`@app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt`:
- Around line 126-130: All Quillpad timestamps must be normalized to
milliseconds consistently; verify the source (Quillpad timestamps) and, if they
are in seconds, multiply every timestamp by 1000 before using or wrapping with
Date(), specifically change the timestamp expression used when building
AudioAttachment (currently using modifiedDate * 1000) and update the
Date(it.date) call and the places that pass creationDate and modifiedDate
directly so they all use the same normalized value (e.g., normalizeCreated =
creationDate * 1000, normalizeModified = modifiedDate * 1000) before
constructing Date(...) or assigning to timestamp fields in QuillpadImporter.kt.

In `@app/src/main/java/com/philkes/notallyx/utils/IOExtensions.kt`:
- Around line 290-300: The File.moveAllFiles extension currently ignores
renameTo() failures causing silent partial moves; update moveAllFiles to check
each file.renameTo(targetFile) result and fail fast on false by throwing an
IOException (or propagate an error) with context (source file and targetFile) so
callers like the Quillpad import path see the failure; ensure to keep the
mkdirs() creation logic but validate renameTo for every file in listFiles()
inside moveAllFiles and surface the error instead of swallowing it.

In `@app/src/main/java/com/philkes/notallyx/utils/NotallyUtils.kt`:
- Around line 18-30: The frequency mapping inside
NotallyReminderJson?.toNotallyXReminder() currently only handles "DAILY" and
"MONTHLY" and must be extended: add a "WEEKLY" case mapping to Repetition(1,
RepetitionTimeUnit.WEEKS) and expand the when(...) on getSafeString("frequency")
to handle other Notally frequency tokens (or normalize case with .uppercase())
rather than falling through to null; for unknown tokens, either translate them
to the closest Repetition/RepetitionTimeUnit or emit a warning/log so the
recurrence isn't silently lost when constructing the Reminder in
toNotallyXReminder().

In `@app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt`:
- Around line 31-32: The call to
application.getExternalFilesDir(Environment.MEDIA_MOUNTED) is incorrect and dead
code; either remove that line or change the argument to null so it requests the
app-specific external files root. Locate the
ApplicationProvider.getApplicationContext() usage in NotesImporterTest.kt and
update the getExternalFilesDir(...) call (or delete it) and ensure tests
continue to rely on getCurrentMediaRoot() for external media access.

In
`@app/src/test/kotlin/com/philkes/notallyx/data/imports/quillpad/QuillpadImporterTest.kt`:
- Around line 171-199: The test failing because it expects non-standard
"image/jpg" — update the MIME normalization in the importer where it builds the
MIME type (the code around the MIME creation in QuillpadImporter, currently
doing "image/$extension" near the MIME derivation lines) to map "jpg" to "jpeg"
(and similarly "tif" to "tiff" if desired) before composing the MIME string,
then keep the test expecting standard "image/jpeg" (or alternatively change the
test expectation to "image/jpeg"); locate the logic in QuillpadImporter (the
function that converts attachments into FileAttachment and sets the MIME) and
normalize extensions like "jpg" -> "jpeg" prior to forming the MIME type.
- Around line 277-281: Timestamps for reminders are being passed as seconds into
Date(...) causing a unit mismatch; update the QuillpadImporter code where
reminders are converted (the usage of Date(it.date) in the reminder mapping
inside parseToBaseNote()/QuillpadImporter) to multiply the incoming epoch
seconds by 1000 (Date(it.date * 1000)) to match the audio conversion pattern
(modifiedDate * 1000), and update the test expectation in QuillpadImporterTest
to expect Date(1776012540000L) (or 1776012540 * 1000) for the reminder.

In `@documentation/docs/features/import-other-apps.mdx`:
- Around line 16-22: Update the "Available Imports" list in the documentation by
adding the JSON importer entry and align the combined files label with the
in-app chooser; specifically, add an item for the JSON importer (e.g., "JSON
Importer") to the list and change the existing "Plain Text Files" / "Markdown
Files" entries to the single combined label used in-app ("Markdown / Plain Text
Files") so the docs match the chooser options shown to users.

---

Nitpick comments:
In
`@app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt`:
- Around line 77-80: Remove or use the unused variables noteReminders, noteTags,
and tagMap in QuillpadImporter.kt: either delete the lines that compute
noteReminders, noteTags, and tagMap (since toBaseNote reads quillpadNote.tags
and quillpadNote.reminders directly), or modify toBaseNote (or its caller) to
look up tags and reminders by noteId using noteTags, noteReminders and resolve
tag names via tagMap so those computed maps are actually consumed; reference
noteReminders, noteTags, tagMap and the toBaseNote function when making the
change.
- Around line 43-48: The QuillpadImporter.import signature currently returns
Pair<List<BaseNote>, File> but the ExternalImporter interface declares
Pair<List<BaseNote>, File?>; update QuillpadImporter.import to return
Pair<List<BaseNote>, File?> (nullable File) to match the interface (or, if you
intentionally guarantee a non-null File across all importers, update the
ExternalImporter interface instead); adjust any usages of
QuillpadImporter.import or the returned pair to handle a nullable File, and
ensure the method implementation returns null where appropriate when no File is
produced.

In
`@app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/settings/SettingsFragment.kt`:
- Around line 541-558: The code currently maps the dialog selection back to an
importer using ImportSource.entries[which - 1], which will break if enum order
or dialog list changes; instead build and reuse the actual chooser list used to
create the adapter (the list passed in alongside notallyItem and
Display::getIconId) — e.g., create a local val chooserList = notallyItem +
ImportSource.entries.toMutableList() and pass that to setAdapter, then set
selectedImportSource by reading chooserList[which] (or chooserList[which - 1] if
you keep the notallyItem header) so the selected value is taken directly from
the same list rather than re-deriving via ImportSource.entries. Ensure you
update the selection logic around selectedImportSource and the special-case
check for the notallyItem header to use the same chooserList indexing.

In `@app/src/main/java/com/philkes/notallyx/utils/backup/ImportExtensions.kt`:
- Around line 69-90: getOptionalColumns currently returns whatever columns exist
which can hide missing required fields; change it to start from an explicit
required projection (e.g., the fixed core fields used by toBaseNote such as id,
type, folder, title, body) and then append only truly optional columns found in
the DB; validate that all required columns are present and throw or log a clear
error if any required column (referenced by toBaseNote) is missing, and keep
your existing special-case for "body" using SUBSTR with MAX_BODY_CHAR_LENGTH
when building the final projection array in getOptionalColumns.

In `@app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt`:
- Around line 39-145: Add a regression test for Notally by adding a new `@Test`
that calls testImport(ImportSource.NOTALLY, <expectedCount>) (or
testImport(prepareImportSources(ImportSource.NOTALLY), ImportSource.NOTALLY,
<expectedCount>)) and update prepareImportSources(importSource: ImportSource) to
handle ImportSource.NOTALLY returning the Notally fixture file name (e.g.,
"notally_export.zip" or your fixture name); ensure a corresponding Notally
fixture is present in the test resources so the NotesImporter code path (and the
ImportExtensions.kt reminder → reminders fallback) is exercised.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7252e7cb-2a33-4425-877b-87337a5a0025

📥 Commits

Reviewing files that changed from the base of the PR and between 8e2f8be and dd69146.

⛔ Files ignored due to path filters (2)
  • app/src/test/resources/imports/quillpad/quillpad_backup.zip is excluded by !**/*.zip
  • app/translations.xlsx is excluded by !**/*.xlsx
📒 Files selected for processing (21)
  • README.md
  • app/build.gradle.kts
  • app/src/main/java/com/philkes/notallyx/data/imports/NotesImporter.kt
  • app/src/main/java/com/philkes/notallyx/data/imports/google/GoogleKeepImporter.kt
  • app/src/main/java/com/philkes/notallyx/data/imports/google/GoogleKeepNote.kt
  • app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadBackup.kt
  • app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt
  • app/src/main/java/com/philkes/notallyx/data/model/Converters.kt
  • app/src/main/java/com/philkes/notallyx/data/model/Reminder.kt
  • app/src/main/java/com/philkes/notallyx/presentation/activity/main/fragment/settings/SettingsFragment.kt
  • app/src/main/java/com/philkes/notallyx/presentation/view/misc/TextWithIconAdapter.kt
  • app/src/main/java/com/philkes/notallyx/utils/IOExtensions.kt
  • app/src/main/java/com/philkes/notallyx/utils/NotallyUtils.kt
  • app/src/main/java/com/philkes/notallyx/utils/backup/ImportExtensions.kt
  • app/src/main/res/drawable/icon_notally.xml
  • app/src/main/res/drawable/icon_quillpad.xml
  • app/src/main/res/values/strings.xml
  • app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt
  • app/src/test/kotlin/com/philkes/notallyx/data/imports/quillpad/QuillpadImporterTest.kt
  • documentation/docs/features/import-other-apps.mdx
  • documentation/docs/intro.md

Comment thread app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadBackup.kt Outdated
Comment thread app/src/main/java/com/philkes/notallyx/utils/IOExtensions.kt
Comment thread app/src/main/java/com/philkes/notallyx/utils/NotallyUtils.kt
Comment thread app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt Outdated
Comment thread documentation/docs/features/import-other-apps.mdx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/src/main/java/com/philkes/notallyx/utils/MiscExtensions.kt (1)

142-142: Consider explicit return type for public API stability.

This is fine as-is; adding an explicit return type keeps the contract clearer for future edits.

Suggested tweak
-fun Seconds.toMillis() = this * 1000
+fun Seconds.toMillis(): Long = this * 1000L
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/philkes/notallyx/utils/MiscExtensions.kt` at line 142,
Add an explicit return type to the extension function Seconds.toMillis to
stabilize the public API contract; update the function signature for
Seconds.toMillis (the extension) to declare the return type (e.g., : Long) so
callers and future edits have a clear, fixed return type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt`:
- Around line 185-213: The unzip function currently creates a ZipInputStream
(zis) without using Kotlin's use{} so exceptions can leak the stream; wrap
ZipInputStream(inputStream) in a use { zis -> ... } block around the entire
extraction loop in unzip, move zis.closeEntry() to run inside the loop after
processing each zipEntry, and remove the manual zis.close()/closeEntry() calls
at the end; keep the existing FileOutputStream(newFile).use { ... } and continue
using newFile(...) to create files so resources are properly closed on
exceptions.

---

Nitpick comments:
In `@app/src/main/java/com/philkes/notallyx/utils/MiscExtensions.kt`:
- Line 142: Add an explicit return type to the extension function
Seconds.toMillis to stabilize the public API contract; update the function
signature for Seconds.toMillis (the extension) to declare the return type (e.g.,
: Long) so callers and future edits have a clear, fixed return type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d5e3f1e6-06b4-42fa-84b8-b8900ed912eb

📥 Commits

Reviewing files that changed from the base of the PR and between dd69146 and 0a877a3.

📒 Files selected for processing (7)
  • app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadBackup.kt
  • app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadImporter.kt
  • app/src/main/java/com/philkes/notallyx/utils/IOExtensions.kt
  • app/src/main/java/com/philkes/notallyx/utils/MiscExtensions.kt
  • app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt
  • app/src/test/kotlin/com/philkes/notallyx/data/imports/quillpad/QuillpadImporterTest.kt
  • documentation/docs/features/import-other-apps.mdx
✅ Files skipped from review due to trivial changes (3)
  • documentation/docs/features/import-other-apps.mdx
  • app/src/test/kotlin/com/philkes/notallyx/data/imports/NotesImporterTest.kt
  • app/src/main/java/com/philkes/notallyx/data/imports/quillpad/QuillpadBackup.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/main/java/com/philkes/notallyx/utils/IOExtensions.kt
  • app/src/test/kotlin/com/philkes/notallyx/data/imports/quillpad/QuillpadImporterTest.kt

@Crustack Crustack merged commit 5f5a625 into main Apr 12, 2026
1 check passed
@Crustack Crustack deleted the feat/quillpad-import branch April 12, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Quillpad import Import from Nottaly

1 participant