Skip to content

Commit 9175689

Browse files
committed
feat: remember preview/edit mode per note
Adds a `noteMode` column to the Note table (DB version 29 → 30) to persist each note's view mode independently. When a user explicitly toggles Preview/Edit/DirectEdit, the new mode is saved immediately to the note, overriding the global SharedPreferences setting for that specific note. Notes without a stored per-note mode continue to follow the global preference as before. Resolves the TODO comment in EditNoteActivity.close(). AI-assisted: Claude Code (Sonnet 4.6) Signed-off-by: Jan C. Borchardt <925062+jancborchardt@users.noreply.github.com>
1 parent eec74d5 commit 9175689

8 files changed

Lines changed: 1593 additions & 26 deletions

File tree

app/schemas/it.niedermann.owncloud.notes.persistence.NotesDatabase/29.json

Lines changed: 756 additions & 0 deletions
Large diffs are not rendered by default.

app/schemas/it.niedermann.owncloud.notes.persistence.NotesDatabase/30.json

Lines changed: 762 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -249,17 +249,31 @@ private void replaceFragment() {
249249

250250

251251
/**
252-
* Returns the preferred mode for the account. If the mode is "remember last" the last mode is returned.
253-
* If the mode is "direct edit" and the account does not support direct edit, the default mode is returned.
252+
* Returns the preferred mode for the note. Checks the per-note stored mode first, then falls
253+
* back to the global preference. If the mode is "remember last" the last mode is returned.
254+
* If the mode is "direct edit" and the account does not support direct edit, edit mode is returned.
254255
*/
255-
private String getPreferenceMode(long accountId) {
256+
private String getPreferenceMode(long accountId, long noteId) {
257+
final var defaultMode = getString(R.string.pref_value_mode_edit);
258+
final var prefValueDirectEdit = getString(R.string.pref_value_mode_direct_edit);
259+
260+
if (noteId > 0) {
261+
final Note note = repo.getNoteById(noteId);
262+
if (note != null && note.getNoteMode() != null) {
263+
final String noteMode = note.getNoteMode();
264+
if (noteMode.equals(prefValueDirectEdit)) {
265+
final Account accountById = repo.getAccountById(accountId);
266+
if (accountById == null || !accountById.isDirectEditingAvailable()) {
267+
return defaultMode;
268+
}
269+
}
270+
return noteMode;
271+
}
272+
}
256273

257274
final var prefKeyNoteMode = getString(R.string.pref_key_note_mode);
258275
final var prefKeyLastMode = getString(R.string.pref_key_last_note_mode);
259-
final var defaultMode = getString(R.string.pref_value_mode_edit);
260276
final var prefValueLast = getString(R.string.pref_value_mode_last);
261-
final var prefValueDirectEdit = getString(R.string.pref_value_mode_direct_edit);
262-
263277

264278
final var preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
265279
final String modePreference = preferences.getString(prefKeyNoteMode, defaultMode);
@@ -282,7 +296,7 @@ private String getPreferenceMode(long accountId) {
282296

283297
private BaseNoteFragment getNoteFragment(long accountId, long noteId, final @Nullable String modePref) {
284298

285-
final var effectiveMode = modePref == null ? getPreferenceMode(accountId) : modePref;
299+
final var effectiveMode = modePref == null ? getPreferenceMode(accountId, noteId) : modePref;
286300

287301
final var prefValueEdit = getString(R.string.pref_value_mode_edit);
288302
final var prefValueDirectEdit = getString(R.string.pref_value_mode_direct_edit);
@@ -302,7 +316,7 @@ private BaseNoteFragment getNoteFragment(long accountId, long noteId, final @Nul
302316

303317
@NonNull
304318
private BaseNoteFragment getNewNoteFragment(Note newNote) {
305-
final var mode = getPreferenceMode(getAccountId());
319+
final var mode = getPreferenceMode(getAccountId(), 0);
306320

307321
final var prefValueDirectEdit = getString(R.string.pref_value_mode_direct_edit);
308322

@@ -397,18 +411,6 @@ public boolean onOptionsItemSelected(MenuItem item) {
397411
* Send result and closes the Activity
398412
*/
399413
public void close() {
400-
/* TODO enhancement: store last mode in note
401-
* for cross device functionality per note mode should be stored on the server.
402-
*/
403-
final var preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
404-
final String prefKeyLastMode = getString(R.string.pref_key_last_note_mode);
405-
if (fragment instanceof NoteEditFragment) {
406-
preferences.edit().putString(prefKeyLastMode, getString(R.string.pref_value_mode_edit)).apply();
407-
} else if (fragment instanceof NotePreviewFragment) {
408-
preferences.edit().putString(prefKeyLastMode, getString(R.string.pref_value_mode_preview)).apply();
409-
} else if (fragment instanceof NoteDirectEditFragment) {
410-
preferences.edit().putString(prefKeyLastMode, getString(R.string.pref_value_mode_direct_edit)).apply();
411-
}
412414
fragment.onCloseNote();
413415

414416
if(isTaskRoot()) {
@@ -435,12 +437,19 @@ public void onNoteUpdated(Note note) {
435437

436438
@Override
437439
public void changeMode(@NonNull Mode mode, boolean reloadNote) {
438-
switch (mode) {
439-
case EDIT -> launchExistingNote(getAccountId(), getNoteId(), getString(R.string.pref_value_mode_edit), reloadNote);
440-
case PREVIEW -> launchExistingNote(getAccountId(), getNoteId(), getString(R.string.pref_value_mode_preview), reloadNote);
441-
case DIRECT_EDIT -> launchExistingNote(getAccountId(), getNoteId(), getString(R.string.pref_value_mode_direct_edit), reloadNote);
440+
final String modeString = switch (mode) {
441+
case EDIT -> getString(R.string.pref_value_mode_edit);
442+
case PREVIEW -> getString(R.string.pref_value_mode_preview);
443+
case DIRECT_EDIT -> getString(R.string.pref_value_mode_direct_edit);
442444
default -> throw new IllegalStateException("Unknown mode: " + mode);
445+
};
446+
final long noteId = getNoteId();
447+
if (noteId > 0) {
448+
repo.updateNoteMode(noteId, modeString);
443449
}
450+
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
451+
.edit().putString(getString(R.string.pref_key_last_note_mode), modeString).apply();
452+
launchExistingNote(getAccountId(), noteId, modeString, reloadNote);
444453
}
445454

446455

app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import it.niedermann.owncloud.notes.persistence.migration.Migration_22_23;
4747
import it.niedermann.owncloud.notes.persistence.migration.Migration_23_24;
4848
import it.niedermann.owncloud.notes.persistence.migration.Migration_24_25;
49+
import it.niedermann.owncloud.notes.persistence.migration.Migration_29_30;
4950
import it.niedermann.owncloud.notes.persistence.migration.Migration_9_10;
5051
import it.niedermann.owncloud.notes.shared.model.Capabilities;
5152

@@ -58,7 +59,7 @@
5859
NotesListWidgetData.class,
5960
ShareEntity.class,
6061
Capabilities.class
61-
}, version = 29,
62+
}, version = 30,
6263
autoMigrations = {
6364
@AutoMigration(from = 25, to = 26),
6465
@AutoMigration(from = 26, to = 27),
@@ -101,7 +102,8 @@ private static NotesDatabase create(final Context context) {
101102
new Migration_21_22(context),
102103
new Migration_22_23(),
103104
new Migration_23_24(context),
104-
new Migration_24_25()
105+
new Migration_24_25(),
106+
new Migration_29_30()
105107
)
106108
.addCallback(new RoomDatabase.Callback() {
107109
@Override

app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ public void updateScrollY(long id, int scrollY) {
372372
db.getNoteDao().updateScrollY(id, scrollY);
373373
}
374374

375+
public void updateNoteMode(long id, @Nullable String noteMode) {
376+
db.getNoteDao().updateNoteMode(id, noteMode);
377+
}
378+
375379
public LiveData<List<CategoryWithNotesCount>> searchCategories$(Long accountId, String searchTerm) {
376380
return db.getNoteDao().searchCategories$(accountId, searchTerm);
377381
}

app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package it.niedermann.owncloud.notes.persistence.dao;
88

9+
import androidx.annotation.Nullable;
910
import androidx.lifecycle.LiveData;
1011
import androidx.room.Dao;
1112
import androidx.room.Insert;
@@ -125,6 +126,9 @@ public interface NoteDao {
125126
@Query("UPDATE NOTE SET scrollY = :scrollY WHERE id = :id")
126127
void updateScrollY(long id, int scrollY);
127128

129+
@Query("UPDATE NOTE SET noteMode = :noteMode WHERE id = :id")
130+
void updateNoteMode(long id, @Nullable String noteMode);
131+
128132
@Query("UPDATE NOTE SET status = :status WHERE id = :id")
129133
void updateStatus(long id, DBStatus status);
130134

app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/Note.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ public class Note implements Serializable, Item {
103103
@ColumnInfo(defaultValue = "0")
104104
private int scrollY = 0;
105105

106+
@Nullable
107+
@ColumnInfo(defaultValue = "NULL")
108+
private String noteMode;
109+
106110
public Note() {
107111
super();
108112
}
@@ -272,6 +276,15 @@ public void setScrollY(int scrollY) {
272276
this.scrollY = scrollY;
273277
}
274278

279+
@Nullable
280+
public String getNoteMode() {
281+
return noteMode;
282+
}
283+
284+
public void setNoteMode(@Nullable String noteMode) {
285+
this.noteMode = noteMode;
286+
}
287+
275288
@Override
276289
public boolean equals(Object o) {
277290
if (this == o) return true;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Nextcloud Notes - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
package it.niedermann.owncloud.notes.persistence.migration
8+
9+
import androidx.room.migration.Migration
10+
import androidx.sqlite.db.SupportSQLiteDatabase
11+
12+
@Suppress("ClassName", "Detekt.ClassNaming")
13+
class Migration_29_30 : Migration(29, 30) {
14+
override fun migrate(db: SupportSQLiteDatabase) {
15+
db.execSQL("ALTER TABLE Note ADD COLUMN noteMode TEXT DEFAULT NULL")
16+
}
17+
}

0 commit comments

Comments
 (0)