Skip to content

Comments

fixes for #186 and #160, #161, #162#203

Merged
Ethran merged 7 commits intomainfrom
dev
Feb 7, 2026
Merged

fixes for #186 and #160, #161, #162#203
Ethran merged 7 commits intomainfrom
dev

Conversation

@Ethran
Copy link
Owner

@Ethran Ethran commented Feb 7, 2026

fixes for #186 and #160, #161, #162

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR appears to address crashes/edge-cases referenced by #186 and #161 by improving external link handling in Settings and making stroke persistence more resilient to SQLite uniqueness conflicts in the editor.

Changes:

  • Replaced direct startActivity URL launching with a shared openInBrowser(...) helper and added an error snackbar on ActivityNotFoundException.
  • Switched Settings tab titles to stringResource(...) for Compose-friendly localization lookup.
  • Wrapped stroke insertion in a try/catch for SQLiteConstraintException and attempted a fallback update(...) on conflict.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
app/src/main/java/com/ethran/notable/ui/views/Settings.kt Adds openInBrowser helper and routes Settings external links through it, plus Compose string changes.
app/src/main/java/com/ethran/notable/editor/PageView.kt Handles stroke insert constraint exceptions by falling back to update and moves stroke persistence to an IO coroutine.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 352 to +355
private fun saveStrokesToPersistLayer(strokes: List<Stroke>) {
dbStrokes.create(strokes)
coroutineScope.launch(Dispatchers.IO) {
try {
dbStrokes.create(strokes)
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

saveStrokesToPersistLayer now launches a DB write on the coroutineScope passed into PageView. In EditorView, that scope comes from rememberCoroutineScope() and will be cancelled when the composable leaves composition; this means stroke persistence can be cancelled on navigation/close and strokes may never be written to the DB. Consider using a dedicated persistence scope in PageView (e.g., SupervisorJob()+Dispatchers.IO cancelled explicitly in disposeOldPage()), or otherwise ensure persistence isn't cancelled mid-write.

Copilot uses AI. Check for mistakes.
Comment on lines 354 to 363
try {
dbStrokes.create(strokes)
} catch (_: SQLiteConstraintException) {
// There were some rare bugs when strokes weren't unique when inserting from history
// I'm not sure if its still a problem, lets just show the message
logAndShowError(
"saveStrokesToPersistLayer",
"Attempted to create strokes that already exist"
)
dbStrokes.update(strokes)
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Catching SQLiteConstraintException and then calling dbStrokes.update(strokes) can still lose data: Room's @Insert for a list runs in a transaction by default, so if any stroke conflicts, the entire insert may abort and none of the new strokes are inserted. @Update will not insert missing rows, so any genuinely-new strokes in this batch will be dropped. Prefer an actual upsert approach (e.g., @Insert(onConflict = REPLACE/IGNORE) + follow-up update for ignored rows, or Room @Upsert if available).

Suggested change
try {
dbStrokes.create(strokes)
} catch (_: SQLiteConstraintException) {
// There were some rare bugs when strokes weren't unique when inserting from history
// I'm not sure if its still a problem, lets just show the message
logAndShowError(
"saveStrokesToPersistLayer",
"Attempted to create strokes that already exist"
)
dbStrokes.update(strokes)
strokes.forEach { stroke ->
try {
// Try to create each stroke individually so a conflict on one
// stroke does not prevent others from being inserted.
dbStrokes.create(listOf(stroke))
} catch (_: SQLiteConstraintException) {
// There were some rare bugs when strokes weren't unique when inserting from history
// I'm not sure if its still a problem, lets just show the message
logAndShowError(
"saveStrokesToPersistLayer",
"Attempted to create strokes that already exist"
)
// Fall back to updating the existing stroke (upsert-like behavior).
dbStrokes.update(listOf(stroke))
}

Copilot uses AI. Check for mistakes.
--AI--
- Add null checks in `FolderConfigDialog` and `FolderSelectionDialog` to prevent crashes when attempting to access a folder that has been deleted.
- Add logging to `FolderRepository` to report when a folder is not found.
…that originally the issue #160 was triggered by user manually deleting db.

--AI--
- Add a check to ensure the database directory is writable before use.
@Ethran Ethran changed the title fixes for #186 and #161 fixes for #186 and #160, #161, #162 Feb 7, 2026
@Ethran Ethran requested a review from Copilot February 7, 2026 10:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 19 to +24
if (!dbDir.exists()) {
dbDir.mkdirs()
}
if (!dbDir.canWrite()) {
throw IllegalStateException("Database directory is not writable")
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Throwing IllegalStateException here will crash the app during AppDatabase.getDatabase() when the external Documents directory isn’t writable (common on newer Android versions without the right permissions/scoped-storage access). Instead of crashing, handle mkdirs() failures explicitly and fall back to an app-private directory (e.g. context.filesDir) or surface a recoverable error path so the app can still start.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@Ethran Ethran merged commit 9d8a219 into main Feb 7, 2026
1 check passed
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.

1 participant