Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#528 Save the excerpt in a separate column #641

Merged
merged 5 commits into from
Dec 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 5 additions & 12 deletions app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import java.io.Serializable;
import java.util.Calendar;

import it.niedermann.owncloud.notes.util.NoteUtil;

/**
* DBNote represents a single note from the local SQLite database with all attributes.
* It extends CloudNote with attributes required for local data management.
Expand All @@ -16,12 +14,12 @@ public class DBNote extends CloudNote implements Item, Serializable {
private long id;
private long accountId;
private DBStatus status;
private String excerpt = "";
private String excerpt;

public DBNote(long id, long remoteId, Calendar modified, String title, String content, boolean favorite, String category, String etag, DBStatus status, long accountId) {
public DBNote(long id, long remoteId, Calendar modified, String title, String content, boolean favorite, String category, String etag, DBStatus status, long accountId, String excerpt) {
super(remoteId, modified, title, content, favorite, category, etag);
this.id = id;
setExcerpt(content);
this.excerpt = excerpt;
this.status = status;
this.accountId = accountId;
}
Expand All @@ -46,17 +44,12 @@ public String getExcerpt() {
return excerpt;
}

public void setExcerptDirectly(String content) {
excerpt = content;
}

private void setExcerpt(String content) {
excerpt = NoteUtil.generateNoteExcerpt(content);
public void setExcerpt(String excerpt) {
this.excerpt = excerpt;
}

public void setContent(String content) {
super.setContent(content);
setExcerpt(content);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private DBNote colorTheNote(DBNote dbNote) {
matcher.start(), matcher.end(), 0);
}

dbNote.setExcerptDirectly(Html.toHtml(spannableString));
dbNote.setExcerpt(Html.toHtml(spannableString));
}

return dbNote;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,31 @@ public class NoteSQLiteOpenHelper extends SQLiteOpenHelper {

private static final String TAG = NoteSQLiteOpenHelper.class.getSimpleName();

private static final int database_version = 9;
private static final int database_version = 10;

private static final String database_name = "OWNCLOUD_NOTES";
private static final String table_notes = "NOTES";
private static final String table_accounts = "ACCOUNTS";

private static final String key_id = "ID";
private static final String key_account_id = "ACCOUNT_ID";
private static final String key_remote_id = "REMOTEID";

private static final String key_url = "URL";
private static final String key_account_name = "ACCOUNT_NAME";
private static final String key_username = "USERNAME";

private static final String key_account_id = "ACCOUNT_ID";
private static final String key_remote_id = "REMOTEID";
private static final String key_status = "STATUS";
private static final String key_title = "TITLE";
private static final String key_modified = "MODIFIED";
private static final String key_content = "CONTENT";
private static final String key_excerpt = "EXCERPT";
private static final String key_favorite = "FAVORITE";
private static final String key_category = "CATEGORY";
private static final String key_etag = "ETAG";

private static final String[] columns = {key_id, key_remote_id, key_status, key_title, key_modified, key_content, key_favorite, key_category, key_etag};
private static final String[] columnsWithoutContent = {key_id, key_remote_id, key_status, key_title, key_modified, key_favorite, key_category, key_etag, key_excerpt};
private static final String[] columns = {key_id, key_remote_id, key_status, key_title, key_modified, key_favorite, key_category, key_etag, key_excerpt, key_content};
private static final String default_order = key_favorite + " DESC, " + key_modified + " DESC";

private static NoteSQLiteOpenHelper instance;
Expand Down Expand Up @@ -118,6 +122,7 @@ private void createNotesTable(@NonNull SQLiteDatabase db, @NonNull String tableN
key_favorite + " INTEGER DEFAULT 0, " +
key_category + " TEXT NOT NULL DEFAULT '', " +
key_etag + " TEXT," +
key_excerpt + " TEXT NOT NULL DEFAULT '', " +
"FOREIGN KEY(" + key_account_id + ") REFERENCES " + table_accounts + "(" + key_id + "))");
createNotesIndexes(db);
}
Expand Down Expand Up @@ -195,9 +200,22 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Add FOREIGN_KEY constraint
final String table_temp = "NOTES_TEMP";
db.execSQL(String.format("ALTER TABLE %s RENAME TO %s", table_notes, table_temp));
createNotesTable(db, table_notes);

db.execSQL(String.format("INSERT INTO %s(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ", table_notes, key_id, key_account_id, key_remote_id, key_status, key_title, key_modified, key_content, key_favorite, key_category, key_etag)
db.execSQL("CREATE TABLE " + table_notes + " ( " +
key_id + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
key_remote_id + " INTEGER, " +
key_account_id + " INTEGER, " +
key_status + " VARCHAR(50), " +
key_title + " TEXT, " +
key_modified + " INTEGER DEFAULT 0, " +
key_content + " TEXT, " +
key_favorite + " INTEGER DEFAULT 0, " +
key_category + " TEXT NOT NULL DEFAULT '', " +
key_etag + " TEXT," +
"FOREIGN KEY(" + key_account_id + ") REFERENCES " + table_accounts + "(" + key_id + "))");
DatabaseIndexUtil.createIndex(db, table_notes, key_remote_id, key_account_id, key_status, key_favorite, key_category, key_modified);

db.execSQL(String.format("INSERT INTO %s(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ", table_notes, key_id, key_account_id, key_remote_id, key_status, key_title, key_modified, key_content, key_favorite, key_category, key_etag)
+ String.format("SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s", key_id, values.get(key_account_id), key_remote_id, key_status, key_title, key_modified, key_content, key_favorite, key_category, key_etag, table_temp));
db.execSQL(String.format("DROP TABLE %s;", table_temp));

Expand All @@ -209,7 +227,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
int[] appWidgetIdsSNW = awm.getAppWidgetIds(new ComponentName(context, SingleNoteWidget.class));

for (int appWidgetId : appWidgetIdsNLW) {
if (sharedPreferences.getInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, -1) >=0) {
if (sharedPreferences.getInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, -1) >= 0) {
editor.putLong(NoteListWidget.ACCOUNT_ID_KEY + appWidgetId, 1);
}
}
Expand Down Expand Up @@ -239,6 +257,16 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
recreateDatabase(db);
}
}
if (oldVersion < 10) {
db.execSQL("ALTER TABLE " + table_notes + " ADD COLUMN " + key_excerpt + " INTEGER NOT NULL DEFAULT ''");
Cursor cursor = db.query(table_notes, new String[]{key_id, key_content}, null, null, null, null, null, null);
while (cursor.moveToNext()) {
ContentValues values = new ContentValues();
values.put(key_excerpt, NoteUtil.generateNoteExcerpt(cursor.getString(1)));
db.update(table_notes, values, key_id + " = ? ", new String[]{cursor.getString(0)});
}
cursor.close();
}
}

@Override
Expand Down Expand Up @@ -271,7 +299,7 @@ public Context getContext() {
* @param note Note
*/
public long addNoteAndSync(long accountId, CloudNote note) {
DBNote dbNote = new DBNote(0, 0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), note.getEtag(), DBStatus.LOCAL_EDITED, accountId);
DBNote dbNote = new DBNote(0, 0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), note.getEtag(), DBStatus.LOCAL_EDITED, accountId, NoteUtil.generateNoteExcerpt(note.getContent()));
long id = addNote(accountId, dbNote);
notifyNotesChanged();
getNoteServerSyncHelper().scheduleSync(true);
Expand All @@ -294,9 +322,11 @@ long addNote(long accountId, CloudNote note) {
}
values.put(key_status, dbNote.getStatus().getTitle());
values.put(key_account_id, dbNote.getAccountId());
values.put(key_excerpt, dbNote.getExcerpt());
} else {
values.put(key_status, DBStatus.VOID.getTitle());
values.put(key_account_id, accountId);
values.put(key_excerpt, NoteUtil.generateNoteExcerpt(note.getContent()));
}
if (note.getRemoteId() > 0) {
values.put(key_remote_id, note.getRemoteId());
Expand All @@ -317,7 +347,7 @@ long addNote(long accountId, CloudNote note) {
* @return requested Note
*/
public DBNote getNote(long accountId, long id) {
List<DBNote> notes = getNotesCustom(accountId, key_id + " = ? AND " + key_status + " != ? AND " + key_account_id + " = ? ", new String[]{String.valueOf(id), DBStatus.LOCAL_DELETED.getTitle(), "" + accountId}, null);
List<DBNote> notes = getNotesCustom(accountId, key_id + " = ? AND " + key_status + " != ? AND " + key_account_id + " = ? ", new String[]{String.valueOf(id), DBStatus.LOCAL_DELETED.getTitle(), "" + accountId}, null, false);
return notes.isEmpty() ? null : notes.get(0);
}

Expand All @@ -331,21 +361,21 @@ public DBNote getNote(long accountId, long id) {
*/
@NonNull
@WorkerThread
private List<DBNote> getNotesCustom(long accountId, @NonNull String selection, @NonNull String[] selectionArgs, @Nullable String orderBy) {
return this.getNotesCustom(accountId, selection, selectionArgs, orderBy, null);
private List<DBNote> getNotesCustom(long accountId, @NonNull String selection, @NonNull String[] selectionArgs, @Nullable String orderBy, boolean pruneContent) {
return this.getNotesCustom(accountId, selection, selectionArgs, orderBy, null, pruneContent);
}

@NonNull
@WorkerThread
private List<DBNote> getNotesCustom(long accountId, @NonNull String selection, @NonNull String[] selectionArgs, @Nullable String orderBy, @Nullable String limit) {
private List<DBNote> getNotesCustom(long accountId, @NonNull String selection, @NonNull String[] selectionArgs, @Nullable String orderBy, @Nullable String limit, boolean pruneContent) {
SQLiteDatabase db = getReadableDatabase();
if (selectionArgs.length > 2) {
Log.v(TAG, selection + " ---- " + selectionArgs[0] + " " + selectionArgs[1] + " " + selectionArgs[2]);
}
Cursor cursor = db.query(table_notes, columns, selection, selectionArgs, null, null, orderBy, limit);
Cursor cursor = db.query(table_notes, pruneContent ? columnsWithoutContent : columns, selection, selectionArgs, null, null, orderBy, limit);
List<DBNote> notes = new ArrayList<>();
while (cursor.moveToNext()) {
notes.add(getNoteFromCursor(accountId, cursor));
notes.add(getNoteFromCursor(accountId, cursor, pruneContent));
}
cursor.close();
return notes;
Expand All @@ -355,19 +385,33 @@ private List<DBNote> getNotesCustom(long accountId, @NonNull String selection, @
* Creates a DBNote object from the current row of a Cursor.
*
* @param cursor database cursor
* @param pruneContent
* @return DBNote
*/
@NonNull
private DBNote getNoteFromCursor(long accountId, @NonNull Cursor cursor) {
private DBNote getNoteFromCursor(long accountId, @NonNull Cursor cursor, boolean pruneContent) {
validateAccountId(accountId);
Calendar modified = Calendar.getInstance();
modified.setTimeInMillis(cursor.getLong(4) * 1000);
return new DBNote(cursor.getLong(0), cursor.getLong(1), modified, cursor.getString(3), cursor.getString(5), cursor.getInt(6) > 0, cursor.getString(7), cursor.getString(8), DBStatus.parse(cursor.getString(2)), accountId);

return new DBNote(
cursor.getLong(0),
cursor.getLong(1),
modified,
cursor.getString(3),
pruneContent ? "" : cursor.getString(9),
cursor.getInt(5) > 0,
cursor.getString(6),
cursor.getString(7),
DBStatus.parse(cursor.getString(2)),
accountId,
cursor.getString(8)
);
}

public void debugPrintFullDB(long accountId) {
validateAccountId(accountId);
List<DBNote> notes = getNotesCustom(accountId, "", new String[]{}, default_order);
List<DBNote> notes = getNotesCustom(accountId, "", new String[]{}, default_order, false);
Log.v(TAG, "Full Database (" + notes.size() + " notes):");
for (DBNote note : notes) {
Log.v(TAG, " " + note);
Expand Down Expand Up @@ -397,14 +441,14 @@ public Map<Long, Long> getIdMap(long accountId) {
@WorkerThread
public List<DBNote> getNotes(long accountId) {
validateAccountId(accountId);
return getNotesCustom(accountId, key_status + " != ? AND " + key_account_id + " = ?", new String[]{DBStatus.LOCAL_DELETED.getTitle(), "" + accountId}, default_order);
return getNotesCustom(accountId, key_status + " != ? AND " + key_account_id + " = ?", new String[]{DBStatus.LOCAL_DELETED.getTitle(), "" + accountId}, default_order, false);
}

@NonNull
@WorkerThread
public List<DBNote> getRecentNotes(long accountId) {
validateAccountId(accountId);
return getNotesCustom(accountId, key_status + " != ? AND " + key_account_id + " = ?", new String[]{DBStatus.LOCAL_DELETED.getTitle(), "" + accountId}, key_modified + " DESC", "4");
return getNotesCustom(accountId, key_status + " != ? AND " + key_account_id + " = ?", new String[]{DBStatus.LOCAL_DELETED.getTitle(), "" + accountId}, key_modified + " DESC", "4", true);
}

/**
Expand Down Expand Up @@ -447,7 +491,7 @@ public List<DBNote> searchNotes(long accountId, @Nullable CharSequence query, @N
}

String order = category == null ? default_order : key_category + ", " + key_title;
return getNotesCustom(accountId, TextUtils.join(" AND ", where), args.toArray(new String[]{}), order);
return getNotesCustom(accountId, TextUtils.join(" AND ", where), args.toArray(new String[]{}), order, true);
}

/**
Expand All @@ -459,7 +503,7 @@ public List<DBNote> searchNotes(long accountId, @Nullable CharSequence query, @N
@WorkerThread
List<DBNote> getLocalModifiedNotes(long accountId) {
validateAccountId(accountId);
return getNotesCustom(accountId, key_status + " != ? AND " + key_account_id + " = ?", new String[]{DBStatus.VOID.getTitle(), "" + accountId}, null);
return getNotesCustom(accountId, key_status + " != ? AND " + key_account_id + " = ?", new String[]{DBStatus.VOID.getTitle(), "" + accountId}, null, false);
}

@NonNull
Expand Down Expand Up @@ -555,9 +599,9 @@ public DBNote updateNoteAndSync(long accountId, @NonNull DBNote oldNote, @Nullab
//debugPrintFullDB();
DBNote newNote;
if (newContent == null) {
newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId);
newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId, oldNote.getExcerpt());
} else {
newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNonEmptyNoteTitle(newContent, getContext()), newContent, oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId);
newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNonEmptyNoteTitle(newContent, getContext()), newContent, oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId, NoteUtil.generateNoteExcerpt(newContent));
}
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
Expand All @@ -566,6 +610,7 @@ public DBNote updateNoteAndSync(long accountId, @NonNull DBNote oldNote, @Nullab
values.put(key_category, newNote.getCategory());
values.put(key_modified, newNote.getModified().getTimeInMillis() / 1000);
values.put(key_content, newNote.getContent());
values.put(key_excerpt, newNote.getExcerpt());
int rows = db.update(table_notes, values, key_id + " = ? AND (" + key_content + " != ? OR " + key_category + " != ?)", new String[]{String.valueOf(newNote.getId()), newNote.getContent(), newNote.getCategory()});
// if data was changed, set new status and schedule sync (with callback); otherwise invoke callback directly.
if (rows > 0) {
Expand Down Expand Up @@ -610,6 +655,7 @@ void updateNote(long id, @NonNull CloudNote remoteNote, @Nullable DBNote forceUn
values.put(key_favorite, remoteNote.isFavorite());
values.put(key_category, remoteNote.getCategory());
values.put(key_etag, remoteNote.getEtag());
values.put(key_excerpt, NoteUtil.generateNoteExcerpt(remoteNote.getContent()));
String whereClause;
String[] whereArgs;
if (forceUnchangedDBNoteState != null) {
Expand Down Expand Up @@ -703,9 +749,8 @@ public boolean hasAccounts() {
}

/**
*
* @param url URL to the root of the used Nextcloud instance without trailing slash
* @param username Username of the account
* @param url URL to the root of the used Nextcloud instance without trailing slash
* @param username Username of the account
* @param accountName Composed by the username and the host of the URL, separated by @-sign
* @throws SQLiteConstraintException in case accountName already exists
*/
Expand All @@ -719,7 +764,6 @@ public void addAccount(@NonNull String url, @NonNull String username, @NonNull S
}

/**
*
* @param accountId account which should be read
* @return a LocalAccount object for the given accountId
*/
Expand Down Expand Up @@ -780,7 +824,6 @@ public LocalAccount getLocalAccountByAccountName(String accountName) {
}

/**
*
* @param accountId the id of the account that should be deleted
* @throws IllegalArgumentException if no account has been deleted by the given accountId
*/
Expand Down Expand Up @@ -813,7 +856,7 @@ void updateETag(long accountId, String etag) {

void updateModified(long accountId, long modified) {
validateAccountId(accountId);
if(modified < 0) {
if (modified < 0) {
throw new IllegalArgumentException("modified must be greater or equal 0");
}
SQLiteDatabase db = this.getWritableDatabase();
Expand All @@ -828,7 +871,7 @@ void updateModified(long accountId, long modified) {
}

private static void validateAccountId(long accountId) {
if(accountId < 1) {
if (accountId < 1) {
throw new IllegalArgumentException("accountId must be greater than 0");
}
}
Expand Down