Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-notes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java')
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java197
1 files changed, 129 insertions, 68 deletions
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java
index 5b0226da..eb608ebe 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java
@@ -22,6 +22,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.preference.PreferenceManager;
+import androidx.core.content.ContextCompat;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
@@ -31,7 +32,6 @@ import org.json.JSONArray;
import org.json.JSONException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
@@ -43,8 +43,6 @@ import java.util.Set;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.activity.EditNoteActivity;
-import it.niedermann.owncloud.notes.android.appwidget.NoteListWidget;
-import it.niedermann.owncloud.notes.android.appwidget.SingleNoteWidget;
import it.niedermann.owncloud.notes.model.ApiVersion;
import it.niedermann.owncloud.notes.model.Capabilities;
import it.niedermann.owncloud.notes.model.Category;
@@ -55,10 +53,15 @@ import it.niedermann.owncloud.notes.model.ISyncCallback;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.model.NavigationAdapter;
import it.niedermann.owncloud.notes.util.CategorySortingMethod;
+import it.niedermann.owncloud.notes.model.NoteListsWidgetData;
import it.niedermann.owncloud.notes.model.SingleNoteWidgetData;
+import it.niedermann.owncloud.notes.util.ColorUtil;
import it.niedermann.owncloud.notes.util.NoteUtil;
import static it.niedermann.owncloud.notes.android.activity.EditNoteActivity.ACTION_SHORTCUT;
+import static it.niedermann.owncloud.notes.android.appwidget.NoteListWidget.updateNoteListWidgets;
+import static it.niedermann.owncloud.notes.android.appwidget.SingleNoteWidget.updateSingleNoteWidgets;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_CATEGORY;
/**
* Helps to add, get, update and delete Notes with the option to trigger a Resync with the Server.
@@ -95,9 +98,9 @@ public class NotesDatabase extends AbstractNotesDatabase {
* @param note Note
*/
public long addNoteAndSync(SingleSignOnAccount ssoAccount, 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, NoteUtil.generateNoteExcerpt(note.getContent()));
+ 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()), 0);
long id = addNote(accountId, dbNote);
- notifyNotesChanged();
+ notifyWidgets();
getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
return id;
}
@@ -110,7 +113,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
long addNote(long accountId, CloudNote note) {
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(11);
if (note instanceof DBNote) {
DBNote dbNote = (DBNote) note;
if (dbNote.getId() > 0) {
@@ -141,7 +144,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
addNoteAndSync(ssoAccount, newAccountId, new CloudNote(0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), null));
deleteNoteAndSync(ssoAccount, note.getId());
- notifyNotesChanged();
+ notifyWidgets();
getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
}
@@ -215,8 +218,8 @@ public class NotesDatabase extends AbstractNotesDatabase {
if (selectionArgs.length > 2) {
Log.v(TAG, selection + " ---- " + selectionArgs[0] + " " + selectionArgs[1] + " " + selectionArgs[2]);
}
- String cols = String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s",
- key_id, key_remote_id, key_status, key_title, key_modified, key_favorite, key_category_title, key_etag, key_excerpt);
+ String cols = String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
+ key_id, key_remote_id, key_status, key_title, key_modified, key_favorite, key_category_title, key_etag, key_excerpt, key_scroll_y);
if (!pruneContent) {
cols = String.format("%s, %s", cols, key_content);
}
@@ -249,13 +252,14 @@ public class NotesDatabase extends AbstractNotesDatabase {
cursor.getLong(1),
modified,
cursor.getString(3),
- pruneContent ? "" : cursor.getString(9),
+ pruneContent ? "" : cursor.getString(10),
cursor.getInt(5) > 0,
cursor.getString(6),
cursor.getString(7),
DBStatus.parse(cursor.getString(2)),
accountId,
- cursor.getString(8)
+ cursor.getString(8),
+ cursor.getInt(9)
);
}
@@ -399,7 +403,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
@NonNull
@WorkerThread
- public List<NavigationAdapter.NavigationItem> getCategories(long accountId) {
+ public List<NavigationAdapter.CategoryNavigationItem> getCategories(long accountId) {
return searchCategories(accountId, null);
}
@@ -415,9 +419,9 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
@NonNull
@WorkerThread
- public List<NavigationAdapter.NavigationItem> searchCategories(long accountId, String search) {
+ public List<NavigationAdapter.CategoryNavigationItem> searchCategories(long accountId, String search) {
validateAccountId(accountId);
- String columns = key_category_title + ", COUNT(*)";
+ String columns = key_category_id + ", " + key_category_title + ", COUNT(*)";
String selection = key_status + " != ? AND " +
key_category_account_id + " = ? AND " +
key_category_title + " LIKE ? " +
@@ -432,10 +436,11 @@ public class NotesDatabase extends AbstractNotesDatabase {
Cursor cursor = getReadableDatabase().rawQuery(rawQuery,
new String[]{DBStatus.LOCAL_DELETED.getTitle(), String.valueOf(accountId),
search == null ? "%" : "%" + search.trim() + "%"});
- List<NavigationAdapter.NavigationItem> categories = new ArrayList<>(cursor.getCount());
+
+ List<NavigationAdapter.CategoryNavigationItem> categories = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
Resources res = getContext().getResources();
- String category = cursor.getString(0).toLowerCase();
+ String category = cursor.getString(1).toLowerCase();
int icon = NavigationAdapter.ICON_FOLDER;
if (category.equals(res.getString(R.string.category_music).toLowerCase())) {
icon = R.drawable.ic_library_music_grey600_24dp;
@@ -444,18 +449,31 @@ public class NotesDatabase extends AbstractNotesDatabase {
} else if (category.equals(res.getString(R.string.category_work).toLowerCase())) {
icon = R.drawable.ic_work_grey600_24dp;
}
- categories.add(new NavigationAdapter.NavigationItem("category:" + cursor.getString(0), cursor.getString(0), cursor.getInt(1), icon));
+ categories.add(new NavigationAdapter.CategoryNavigationItem("category:" + cursor.getString(1), cursor.getString(1), cursor.getInt(2), icon, cursor.getLong(0)));
}
cursor.close();
return categories;
}
+ public String getCategoryTitleById(long accountId, long categoryId) {
+ validateAccountId(accountId);
+ final String categoryTitle;
+ final Cursor cursor = getReadableDatabase().query(table_category, new String[]{key_category_title}, key_category_id + " = ?", new String[]{String.valueOf(categoryId)}, null, null, null);
+ if (cursor.moveToFirst()) {
+ categoryTitle = cursor.getString(0);
+ } else {
+ categoryTitle = null;
+ }
+ cursor.close();
+ return categoryTitle;
+ }
+
public void toggleFavorite(SingleSignOnAccount ssoAccount, @NonNull DBNote note, @Nullable ISyncCallback callback) {
note.setFavorite(!note.isFavorite());
note.setStatus(DBStatus.LOCAL_EDITED);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(2);
values.put(key_status, note.getStatus().getTitle());
values.put(key_favorite, note.isFavorite() ? "1" : "0");
db.update(table_notes, values, key_id + " = ?", new String[]{String.valueOf(note.getId())});
@@ -479,7 +497,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
note.setCategory(category);
note.setStatus(DBStatus.LOCAL_EDITED);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(2);
values.put(key_status, note.getStatus().getTitle());
int id = getCategoryIdByTitle(note.getAccountId(), note.getCategory());
values.put(key_category, id);
@@ -494,7 +512,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
private long addCategory(long accountId, @NonNull String title) {
validateAccountId(accountId);
SQLiteDatabase db = getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(2);
values.put(key_category_account_id, accountId);
values.put(key_category_title, title);
return db.insert(table_category, null, values);
@@ -513,23 +531,24 @@ public class NotesDatabase extends AbstractNotesDatabase {
//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, oldNote.getExcerpt());
+ 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(), oldNote.getScrollY());
} 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, NoteUtil.generateNoteExcerpt(newContent));
+ 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), oldNote.getScrollY());
}
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(7);
values.put(key_status, newNote.getStatus().getTitle());
values.put(key_title, newNote.getTitle());
values.put(key_category, getCategoryIdByTitle(newNote.getAccountId(), newNote.getCategory()));
values.put(key_modified, newNote.getModified().getTimeInMillis() / 1000);
values.put(key_content, newNote.getContent());
values.put(key_excerpt, newNote.getExcerpt());
+ values.put(key_scroll_y, newNote.getScrollY());
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()});
removeEmptyCategory(accountId);
// if data was changed, set new status and schedule sync (with callback); otherwise invoke callback directly.
if (rows > 0) {
- notifyNotesChanged();
+ notifyWidgets();
if (callback != null) {
serverSyncHelper.addCallbackPush(ssoAccount, callback);
}
@@ -543,6 +562,14 @@ public class NotesDatabase extends AbstractNotesDatabase {
}
}
+ public void updateScrollY(long noteId, int scrollY) {
+ Log.e(TAG, "Updated scrollY: " + scrollY);
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues(1);
+ values.put(key_scroll_y, scrollY);
+ db.update(table_notes, values, key_id + " = ? ", new String[]{String.valueOf(noteId)});
+ }
+
/**
* Updates a single Note with data from the server, (if it was not modified locally).
* Thereby, an optimistic concurrency control is realized in order to prevent conflicts arising due to parallel changes from the UI and synchronization.
@@ -556,7 +583,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
SQLiteDatabase db = this.getWritableDatabase();
// First, update the remote ID, since this field cannot be changed in parallel, but have to be updated always.
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(8);
values.put(key_remote_id, remoteNote.getRemoteId());
db.update(table_notes, values, key_id + " = ?", new String[]{String.valueOf(id)});
@@ -599,24 +626,28 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
public void deleteNoteAndSync(SingleSignOnAccount ssoAccount, long id) {
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_status, DBStatus.LOCAL_DELETED.getTitle());
db.update(table_notes,
values,
key_id + " = ?",
new String[]{String.valueOf(id)});
- notifyNotesChanged();
+ notifyWidgets();
getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ShortcutManager shortcutManager = getContext().getSystemService(ShortcutManager.class);
- shortcutManager.getPinnedShortcuts().forEach((shortcut) -> {
- String shortcutId = id + "";
- if (shortcut.getId().equals(shortcutId)) {
- Log.v(TAG, "Removing shortcut for " + shortcutId);
- shortcutManager.disableShortcuts(Collections.singletonList(shortcutId), getContext().getResources().getString(R.string.note_has_been_deleted));
- }
- });
+ if (shortcutManager != null) {
+ shortcutManager.getPinnedShortcuts().forEach((shortcut) -> {
+ String shortcutId = id + "";
+ if (shortcut.getId().equals(shortcutId)) {
+ Log.v(TAG, "Removing shortcut for " + shortcutId);
+ shortcutManager.disableShortcuts(Collections.singletonList(shortcutId), getContext().getResources().getString(R.string.note_has_been_deleted));
+ }
+ });
+ } else {
+ Log.e(TAG, ShortcutManager.class.getSimpleName() + "is null.");
+ }
}
}
@@ -638,7 +669,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
/**
* Notify about changed notes.
*/
- protected void notifyNotesChanged() {
+ protected void notifyWidgets() {
updateSingleNoteWidgets(getContext());
updateNoteListWidgets(getContext());
}
@@ -674,24 +705,6 @@ public class NotesDatabase extends AbstractNotesDatabase {
}).start();
}
- /**
- * Update single note widget, if the note data was changed.
- */
- private static void updateSingleNoteWidgets(Context context) {
- Intent intent = new Intent(context, SingleNoteWidget.class);
- intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
- context.sendBroadcast(intent);
- }
-
- /**
- * Update note list widgets, if the note data was changed.
- */
- private static void updateNoteListWidgets(Context context) {
- Intent intent = new Intent(context, NoteListWidget.class);
- intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
- context.sendBroadcast(intent);
- }
-
public boolean hasAccounts() {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), table_accounts) > 0;
}
@@ -705,14 +718,13 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
public void addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities) throws SQLiteConstraintException {
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(4);
values.put(key_url, url);
values.put(key_username, username);
values.put(key_account_name, accountName);
- values.put(key_color, capabilities.getColor().substring(1));
- values.put(key_text_color, capabilities.getTextColor().substring(1));
values.put(key_capabilities_etag, capabilities.getETag());
- db.insertOrThrow(table_accounts, null, values);
+ long accountId = db.insertOrThrow(table_accounts, null, values);
+ updateBrand(accountId, capabilities);
}
/**
@@ -800,15 +812,26 @@ public class NotesDatabase extends AbstractNotesDatabase {
public void updateBrand(long accountId, @NonNull Capabilities capabilities) throws IllegalArgumentException {
validateAccountId(accountId);
- // Validate color format
- Color.parseColor(capabilities.getColor());
- Color.parseColor(capabilities.getTextColor());
+
+ String color;
+ try {
+ color = ColorUtil.formatColorToParsableHexString(capabilities.getColor()).substring(1);
+ } catch (Exception e) {
+ color = String.format("%06X", (0xFFFFFF & ContextCompat.getColor(context, R.color.defaultBrand)));
+ }
+
+ String textColor;
+ try {
+ textColor = ColorUtil.formatColorToParsableHexString(capabilities.getTextColor()).substring(1);
+ } catch (Exception e) {
+ textColor = String.format("%06X", (0xFFFFFF & ContextCompat.getColor(context, android.R.color.white)));
+ }
final SQLiteDatabase db = this.getWritableDatabase();
- final ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues(2);
- values.put(key_color, capabilities.getColor().substring(1));
- values.put(key_text_color, capabilities.getTextColor().substring(1));
+ values.put(key_color, color);
+ values.put(key_text_color, textColor);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -833,7 +856,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
}
if (apiVersions.length() > 0) {
final SQLiteDatabase db = this.getWritableDatabase();
- final ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues(1);
values.put(key_api_version, apiVersion);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -885,7 +908,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
void updateETag(long accountId, String etag) {
validateAccountId(accountId);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_etag, etag);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -898,7 +921,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
public void updateCapabilitiesETag(long accountId, String capabilitiesETag) {
validateAccountId(accountId);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_capabilities_etag, capabilitiesETag);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -914,7 +937,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
throw new IllegalArgumentException("modified must be greater or equal 0");
}
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_modified, modified);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -954,7 +977,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
public void createOrUpdateSingleNoteWidgetData(@NonNull SingleNoteWidgetData data) throws SQLException {
validateAccountId(data.getAccountId());
final SQLiteDatabase db = getWritableDatabase();
- final ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues(4);
values.put(key_id, data.getAppWidgetId());
values.put(key_account_id, data.getAccountId());
values.put(key_note_id, data.getNoteId());
@@ -962,6 +985,44 @@ public class NotesDatabase extends AbstractNotesDatabase {
db.replaceOrThrow(table_widget_single_notes, null, values);
}
+ @NonNull
+ public NoteListsWidgetData getNoteListWidgetData(int appWidgetId) throws NoSuchElementException {
+ NoteListsWidgetData data = new NoteListsWidgetData();
+ final SQLiteDatabase db = getReadableDatabase();
+ final Cursor cursor = db.query(table_widget_note_list, new String[]{key_account_id, key_category_id, key_theme_mode, key_mode}, key_id + " = ?", new String[]{String.valueOf(appWidgetId)}, null, null, null, null);
+ if (cursor.moveToNext()) {
+ data.setAppWidgetId(appWidgetId);
+ data.setAccountId(cursor.getLong(0));
+ data.setCategoryId(cursor.getLong(1));
+ data.setThemeMode(cursor.getInt(2));
+ data.setMode(cursor.getInt(3));
+ } else {
+ throw new NoSuchElementException();
+ }
+ cursor.close();
+ return data;
+ }
+
+ public void removeNoteListWidget(int appWidgetId) {
+ final SQLiteDatabase db = getWritableDatabase();
+ db.delete(table_widget_note_list, key_id + " = ?", new String[]{String.valueOf(appWidgetId)});
+ }
+
+ public void createOrUpdateNoteListWidgetData(@NonNull NoteListsWidgetData data) throws SQLException {
+ validateAccountId(data.getAccountId());
+ final SQLiteDatabase db = getWritableDatabase();
+ final ContentValues values = new ContentValues(5);
+ if (data.getMode() != MODE_DISPLAY_CATEGORY && data.getCategoryId() != null) {
+ throw new UnsupportedOperationException("Cannot create a widget with a categoryId when mode is not " + MODE_DISPLAY_CATEGORY);
+ }
+ values.put(key_id, data.getAppWidgetId());
+ values.put(key_account_id, data.getAccountId());
+ values.put(key_category_id, data.getCategoryId());
+ values.put(key_theme_mode, data.getThemeMode());
+ values.put(key_mode, data.getMode());
+ db.replaceOrThrow(table_widget_note_list, null, values);
+ }
+
private static void validateAccountId(long accountId) {
if (accountId < 1) {
throw new IllegalArgumentException("accountId must be greater than 0");