From accb42b756ed7a26aa8681fdbb7868516b858cb6 Mon Sep 17 00:00:00 2001 From: korelstar Date: Fri, 20 Jan 2017 11:46:20 +0100 Subject: [PATCH] speed-up synchronization and introduce categories --- .../owncloud/notes/model/NoteTest.java | 2 +- .../android/activity/CreateNoteActivity.java | 2 +- .../android/activity/EditNoteActivity.java | 2 +- .../activity/NotesListViewActivity.java | 6 +- .../activity/SelectSingleNoteActivity.java | 2 +- .../notes/android/widget/AllNotesWidget.java | 6 +- .../owncloud/notes/model/CloudNote.java | 29 +++- .../owncloud/notes/model/DBNote.java | 7 +- .../owncloud/notes/model/ItemAdapter.java | 4 + .../persistence/NoteSQLiteOpenHelper.java | 136 ++++++++++++------ .../persistence/NoteServerSyncHelper.java | 19 +-- .../owncloud/notes/util/NotesClient.java | 43 +++--- .../layout/fragment_notes_list_note_item.xml | 20 ++- 13 files changed, 185 insertions(+), 93 deletions(-) diff --git a/app/src/androidTest/java/it/niedermann/owncloud/notes/model/NoteTest.java b/app/src/androidTest/java/it/niedermann/owncloud/notes/model/NoteTest.java index 7e9d14cfd..52f7f67a1 100644 --- a/app/src/androidTest/java/it/niedermann/owncloud/notes/model/NoteTest.java +++ b/app/src/androidTest/java/it/niedermann/owncloud/notes/model/NoteTest.java @@ -11,7 +11,7 @@ public class NoteTest extends TestCase { public void testMarkDownStrip() { - CloudNote note = new CloudNote(0, Calendar.getInstance(), "#Title", "", false); + CloudNote note = new CloudNote(0, Calendar.getInstance(), "#Title", "", false, null, null); assertTrue("Title".equals(note.getTitle())); note.setTitle("* Aufzählung"); assertTrue("Aufzählung".equals(note.getTitle())); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java index 78a3a2952..937313e9b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java @@ -72,7 +72,7 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_create_save: editTextField.setEnabled(false); String content = editTextField.getText().toString(); - NoteSQLiteOpenHelper db = new NoteSQLiteOpenHelper(this); + NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(this); Intent data = new Intent(); data.putExtra(NotesListViewActivity.CREATED_NOTE, db.getNote(db.addNoteAndSync(content))); setResult(RESULT_OK, data); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java index 0ba718e94..d592a792c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java @@ -83,7 +83,7 @@ public void onNext(CharSequence charSequence) { } }); - db = new NoteSQLiteOpenHelper(this); + db = NoteSQLiteOpenHelper.getInstance(this); actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setTitle(note.getTitle()); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java index 50b6e7cb1..bf9030b71 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java @@ -82,7 +82,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_notes_list_view); // Display Data - db = new NoteSQLiteOpenHelper(this); + db = NoteSQLiteOpenHelper.getInstance(this); initList(); refreshList(); @@ -417,7 +417,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } } else if (requestCode == server_settings) { // Create new Instance with new URL and credentials - db = new NoteSQLiteOpenHelper(this); + db = NoteSQLiteOpenHelper.getInstance(this); if(db.getNoteServerSyncHelper().isSyncPossible()) { adapter.removeAll(); swipeRefreshLayout.setRefreshing(true); @@ -468,7 +468,7 @@ public void onNoteClick(int position, View v) { @Override public void onNoteFavoriteClick(int position, View view) { DBNote note = (DBNote) adapter.getItem(position); - NoteSQLiteOpenHelper db = new NoteSQLiteOpenHelper(view.getContext()); + NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(view.getContext()); db.toggleFavorite(note, syncCallBack); adapter.notifyItemChanged(position); refreshList(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java index 412c98078..88b120f8c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java @@ -37,7 +37,7 @@ public void onCreate(Bundle savedInstanceState) { setResult(RESULT_CANCELED); setContentView(R.layout.activity_select_single_note); // Display Data - db = new NoteSQLiteOpenHelper(this); + db = NoteSQLiteOpenHelper.getInstance(this); db.getNoteServerSyncHelper().scheduleSync(false); setListView(db.getNotes()); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/widget/AllNotesWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/android/widget/AllNotesWidget.java index 4aa320b19..f0f2e10af 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/widget/AllNotesWidget.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/widget/AllNotesWidget.java @@ -60,14 +60,14 @@ public StackRemoteViewsFactory(Context context, Intent intent) { mContext = context; mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - NoteSQLiteOpenHelper db = new NoteSQLiteOpenHelper(mContext); + NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(mContext); db.getNoteServerSyncHelper().scheduleSync(false); mWidgetItems = db.getNotes(); - mWidgetItems.add(new DBNote(0, 0, Calendar.getInstance(), "Test-Titel", "Test-Beschreibung", false, DBStatus.VOID)); + mWidgetItems.add(new DBNote(0, 0, Calendar.getInstance(), "Test-Titel", "Test-Beschreibung", false, null, null, DBStatus.VOID)); } public void onCreate() { - mWidgetItems.add(new DBNote(0, 0, Calendar.getInstance(), "Test-Titel", "Test-Beschreibung", false, DBStatus.VOID)); + mWidgetItems.add(new DBNote(0, 0, Calendar.getInstance(), "Test-Titel", "Test-Beschreibung", false, null, null, DBStatus.VOID)); } @Override diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/CloudNote.java b/app/src/main/java/it/niedermann/owncloud/notes/model/CloudNote.java index da1e74b4b..e423a4244 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/model/CloudNote.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/CloudNote.java @@ -18,14 +18,18 @@ public class CloudNote implements Serializable { private Calendar modified = null; private String content = ""; private boolean favorite = false; + private String category = ""; + private String etag = ""; - public CloudNote(long remoteId, Calendar modified, String title, String content, boolean favorite) { + public CloudNote(long remoteId, Calendar modified, String title, String content, boolean favorite, String category, String etag) { this.remoteId = remoteId; if (title != null) setTitle(title); setTitle(title); setContent(content); setFavorite(favorite); + setCategory(category); + setEtag(etag); this.modified = modified; } @@ -51,8 +55,9 @@ public Calendar getModified() { } public String getModified(String format) { - return new SimpleDateFormat(format, Locale.GERMANY) - .format(this.getModified().getTimeInMillis()); + if(modified==null) + return null; + return new SimpleDateFormat(format, Locale.GERMANY) .format(this.getModified().getTimeInMillis()); } public void setModified(Calendar modified) { @@ -75,8 +80,24 @@ public void setFavorite(boolean favorite) { this.favorite = favorite; } + public String getEtag() { + return etag; + } + + public void setEtag(String etag) { + this.etag = etag; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category==null ? "" : category; + } + @Override public String toString() { - return "#" + getRemoteId() + " " + (isFavorite() ? " (*) " : " ") + getTitle() + " (" + getModified(NoteSQLiteOpenHelper.DATE_FORMAT) + ")"; + return "R" + getRemoteId() + " " + (isFavorite() ? " (*) " : " ") + getCategory() + " / " + getTitle() + " (" + getModified(NoteSQLiteOpenHelper.DATE_FORMAT) + " / " + getEtag() + ")"; } } \ No newline at end of file diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java b/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java index 887e33184..d0f6d7ff0 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java @@ -3,7 +3,6 @@ import java.io.Serializable; import java.util.Calendar; -import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper; import it.niedermann.owncloud.notes.util.NoteUtil; /** @@ -16,8 +15,8 @@ public class DBNote extends CloudNote implements Item, Serializable { private DBStatus status; private String excerpt = ""; - public DBNote(long id, long remoteId, Calendar modified, String title, String content, boolean favorite, DBStatus status) { - super(remoteId, modified, title, content, favorite); + public DBNote(long id, long remoteId, Calendar modified, String title, String content, boolean favorite, String category, String etag, DBStatus status) { + super(remoteId, modified, title, content, favorite, category, etag); this.id = id; setExcerpt(content); this.status = status; @@ -55,6 +54,6 @@ public boolean isSection() { @Override public String toString() { - return "#" + getId() + "/R"+getRemoteId()+" " + (isFavorite() ? " (*) " : " ") + getTitle() + " (" + getModified(NoteSQLiteOpenHelper.DATE_FORMAT) + ") " + getStatus(); + return "#"+getId()+"/" + super.toString() + " " + getStatus(); } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java index 3242d7a32..af67882a2 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java @@ -91,6 +91,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) final DBNote note = (DBNote) item; final NoteViewHolder nvHolder = ((NoteViewHolder) holder); nvHolder.noteTitle.setText(note.getTitle()); + nvHolder.noteCategory.setVisibility(note.getCategory().isEmpty() ? View.GONE : View.VISIBLE); + nvHolder.noteCategory.setText(note.getCategory()); nvHolder.noteExcerpt.setText(note.getExcerpt()); nvHolder.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? View.GONE : View.VISIBLE); nvHolder.noteFavorite.setImageResource(note.isFavorite() ? R.drawable.ic_star_grey600_24dp : R.drawable.ic_star_outline_grey600_24dp); @@ -156,6 +158,7 @@ public interface NoteClickListener { public class NoteViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener { // each data item is just a string in this case public TextView noteTitle; + public TextView noteCategory; public TextView noteExcerpt; public ImageView noteStatus; public ImageView noteFavorite; @@ -164,6 +167,7 @@ public class NoteViewHolder extends RecyclerView.ViewHolder implements View.OnLo private NoteViewHolder(View v) { super(v); this.noteTitle = (TextView) v.findViewById(R.id.noteTitle); + this.noteCategory = (TextView) v.findViewById(R.id.noteCategory); this.noteExcerpt = (TextView) v.findViewById(R.id.noteExcerpt); this.noteStatus = (ImageView) v.findViewById(R.id.noteStatus); this.noteFavorite = (ImageView) v.findViewById(R.id.noteFavorite); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java index df9a05a26..bbef5f586 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java @@ -11,8 +11,10 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import it.niedermann.owncloud.notes.model.DBNote; import it.niedermann.owncloud.notes.model.DBStatus; @@ -26,9 +28,10 @@ * Created by stefan on 19.09.15. */ public class NoteSQLiteOpenHelper extends SQLiteOpenHelper { + public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; - private static final int database_version = 6; + private static final int database_version = 7; private static final String database_name = "OWNCLOUD_NOTES"; private static final String table_notes = "NOTES"; private static final String key_id = "ID"; @@ -38,16 +41,28 @@ public class NoteSQLiteOpenHelper extends SQLiteOpenHelper { private static final String key_modified = "MODIFIED"; private static final String key_content = "CONTENT"; private static final String key_favorite = "FAVORITE"; - private static final String[] columns = {key_id, key_remote_id, key_status, key_title, key_modified, key_content, key_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 default_order = key_favorite + " DESC, " + key_modified + " DESC"; + private static NoteSQLiteOpenHelper instance; + private NoteServerSyncHelper serverSyncHelper = null; private Context context = null; - public NoteSQLiteOpenHelper(Context context) { + private NoteSQLiteOpenHelper(Context context) { super(context, database_name, null, database_version); this.context = context.getApplicationContext(); serverSyncHelper = NoteServerSyncHelper.getInstance(this); + //recreateDatabase(getWritableDatabase()); + } + + public static NoteSQLiteOpenHelper getInstance(Context context) { + if(instance==null) + return instance = new NoteSQLiteOpenHelper(context.getApplicationContext()); + else + return instance; } public NoteServerSyncHelper getNoteServerSyncHelper() { @@ -61,19 +76,24 @@ public NoteServerSyncHelper getNoteServerSyncHelper() { */ @Override public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE '" + table_notes + "' ( '" + - key_id + "' INTEGER PRIMARY KEY AUTOINCREMENT, '" + - key_remote_id + "' INTEGER, '" + - key_status + "' VARCHAR(50), '" + - key_title + "' TEXT, '" + - key_modified + "' TEXT, '" + - key_content + "' TEXT, '" + - key_favorite + "' INTEGER DEFAULT 0)"); - // FIXME create index for status and remote_id + db.execSQL("CREATE TABLE " + table_notes + " ( " + + key_id + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + key_remote_id + " INTEGER, " + + key_status + " VARCHAR(50), " + + key_title + " TEXT, " + + key_modified + " TEXT, " + + key_content + " TEXT, " + + key_favorite + " INTEGER DEFAULT 0, " + + key_category + " TEXT NOT NULL DEFAULT '', " + + key_etag + " TEXT)"); + createIndexes(db); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if(oldVersion<3) { + recreateDatabase(db); + } if(oldVersion<4) { clearDatabase(db); } @@ -85,12 +105,44 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if(oldVersion<6) { db.execSQL("ALTER TABLE "+table_notes+" ADD COLUMN "+key_favorite+" INTEGER DEFAULT 0"); } + if(oldVersion<7) { + dropIndexes(db); + db.execSQL("ALTER TABLE "+table_notes+" ADD COLUMN "+key_category+" TEXT NOT NULL DEFAULT ''"); + db.execSQL("ALTER TABLE "+table_notes+" ADD COLUMN "+key_etag+" TEXT"); + createIndexes(db); + } } private void clearDatabase(SQLiteDatabase db) { db.delete(table_notes, null, null); } + private void recreateDatabase(SQLiteDatabase db) { + dropIndexes(db); + db.execSQL("DROP TABLE "+table_notes); + onCreate(db); + } + + private void dropIndexes(SQLiteDatabase db) { + Cursor c = db.query("sqlite_master", new String[]{"name"}, "type=?", new String[]{"index"}, null, null, null); + while (c.moveToNext()) { + db.execSQL( "DROP INDEX "+c.getString(0)); + } + c.close(); + } + + private void createIndexes(SQLiteDatabase db) { + createIndex(db, table_notes, key_remote_id); + createIndex(db, table_notes, key_status); + createIndex(db, table_notes, key_favorite); + createIndex(db, table_notes, key_category); + createIndex(db, table_notes, key_modified); + } + private void createIndex(SQLiteDatabase db, String table, String column) { + String indexName = table+"_"+column+"_idx"; + db.execSQL("CREATE INDEX IF NOT EXISTS "+indexName+" ON "+table+"("+column+")"); + } + public Context getContext() { return context; } @@ -102,7 +154,7 @@ public Context getContext() { */ @SuppressWarnings("UnusedReturnValue") public long addNoteAndSync(String content) { - CloudNote note = new CloudNote(0, Calendar.getInstance(), NoteUtil.generateNoteTitle(content), content, false); + CloudNote note = new CloudNote(0, Calendar.getInstance(), NoteUtil.generateNoteTitle(content), content, false, null, null); return addNoteAndSync(note); } @@ -113,7 +165,7 @@ public long addNoteAndSync(String content) { */ @SuppressWarnings("UnusedReturnValue") public long addNoteAndSync(CloudNote note) { - DBNote dbNote = new DBNote(0, 0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), DBStatus.LOCAL_EDITED); + DBNote dbNote = new DBNote(0, 0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), note.getEtag(), DBStatus.LOCAL_EDITED); long id = addNote(dbNote); getNoteServerSyncHelper().scheduleSync(true); return id; @@ -144,6 +196,8 @@ long addNote(CloudNote note) { values.put(key_modified, note.getModified(NoteSQLiteOpenHelper.DATE_FORMAT)); values.put(key_content, note.getContent()); values.put(key_favorite, note.isFavorite()); + values.put(key_category, note.getCategory()); + values.put(key_etag, note.getEtag()); long id = db.insert(table_notes, null, values); db.close(); return id; @@ -157,23 +211,8 @@ long addNote(CloudNote note) { */ @SuppressWarnings("unused") public DBNote getNote(long id) { - SQLiteDatabase db = this.getReadableDatabase(); - Cursor cursor = - db.query(table_notes, - columns, - key_id + " = ? AND " + key_status + " != ?", - new String[]{String.valueOf(id), DBStatus.LOCAL_DELETED.getTitle()}, - null, - null, - null, - null); - if (cursor == null) { - return null; - } - cursor.moveToFirst(); - DBNote note = getNoteFromCursor(cursor); - cursor.close(); - return note; + List notes = getNotesCustom(key_id + " = ? AND " + key_status + " != ?", new String[]{String.valueOf(id), DBStatus.LOCAL_DELETED.getTitle()}, null); + return notes.isEmpty() ? null : notes.get(0); } /** @@ -187,10 +226,8 @@ private List getNotesCustom(String selection, String[] selectionArgs, St SQLiteDatabase db = getReadableDatabase(); Cursor cursor = db.query(table_notes, columns, selection, selectionArgs, null, null, orderBy); List notes = new ArrayList<>(); - if (cursor.moveToFirst()) { - do { - notes.add(getNoteFromCursor(cursor)); - } while (cursor.moveToNext()); + while (cursor.moveToNext()) { + notes.add(getNoteFromCursor(cursor)); } cursor.close(); return notes; @@ -210,17 +247,28 @@ private DBNote getNoteFromCursor(Cursor cursor) { } catch (ParseException e) { e.printStackTrace(); } - return new DBNote(cursor.getLong(0), cursor.getLong(1), modified, cursor.getString(3), cursor.getString(5), cursor.getInt(6)>0, DBStatus.parse(cursor.getString(2))); + 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))); } public void debugPrintFullDB() { List notes = getNotesCustom("", new String[]{}, default_order); - Log.d(getClass().getSimpleName(), "Full Database:"); + Log.d(getClass().getSimpleName(), "Full Database ("+notes.size()+" notes):"); for (DBNote note : notes) { Log.d(getClass().getSimpleName(), " "+note); } } + public Map getIdMap() { + Map result = new HashMap<>(); + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query(table_notes, new String[]{ key_remote_id, key_id }, key_status + " != ?", new String[]{DBStatus.LOCAL_DELETED.getTitle()}, null, null, null); + while(cursor.moveToNext()) { + result.put(cursor.getLong(0), cursor.getLong(1)); + } + cursor.close(); + return result; + } + /** * Returns a list of all Notes in the Database * @@ -285,9 +333,9 @@ public DBNote updateNoteAndSync(DBNote oldNote, String newContent, ICallback cal debugPrintFullDB(); DBNote newNote; if(newContent==null) { - newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.isFavorite(), DBStatus.LOCAL_EDITED); + newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED); } else { - newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNoteTitle(newContent), newContent, oldNote.isFavorite(), DBStatus.LOCAL_EDITED); + newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNoteTitle(newContent), newContent, oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED); } SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); @@ -339,6 +387,8 @@ int updateNote(long id, CloudNote remoteNote, DBNote forceUnchangedDBNoteState) values.put(key_modified, remoteNote.getModified(DATE_FORMAT)); values.put(key_content, remoteNote.getContent()); values.put(key_favorite, remoteNote.isFavorite()); + values.put(key_category, remoteNote.getCategory()); + values.put(key_etag, remoteNote.getEtag()); String whereClause; String[] whereArgs; if(forceUnchangedDBNoteState!=null) { @@ -346,13 +396,13 @@ int updateNote(long id, CloudNote remoteNote, DBNote forceUnchangedDBNoteState) // update only, if not modified locally during the synchronization // (i.e. all (!) user changeable columns (content, favorite) should still have the same value), // uses reference value gathered at start of synchronization - whereClause = key_id + " = ? AND " + key_content + " = ? AND " + key_favorite + " = ?"; - whereArgs = new String[]{String.valueOf(id), forceUnchangedDBNoteState.getContent(), forceUnchangedDBNoteState.isFavorite()?"1":"0"}; + whereClause = key_id + " = ? AND " + key_content + " = ? AND " + key_favorite + " = ? AND " + key_category + " = ?"; + whereArgs = new String[]{String.valueOf(id), forceUnchangedDBNoteState.getContent(), forceUnchangedDBNoteState.isFavorite()?"1":"0", forceUnchangedDBNoteState.getCategory()}; } else { // used by: NoteServerSyncHelper.SyncTask.pullRemoteChanges() // update only, if not modified locally (i.e. STATUS="") and if modified remotely (i.e. any (!) column has changed) - whereClause = key_id + " = ? AND " + key_status + " = ? AND ("+key_modified+"!=? OR "+key_content+"!=? OR "+key_favorite+"!=?)"; - whereArgs = new String[]{String.valueOf(id), DBStatus.VOID.getTitle(), remoteNote.getModified(DATE_FORMAT), remoteNote.getContent(), remoteNote.isFavorite()?"1":"0"}; + whereClause = key_id + " = ? AND " + key_status + " = ? AND ("+key_modified+"!=? OR "+key_title+"!=? OR "+key_favorite+"!=? OR "+key_category+"!=? OR "+(remoteNote.getEtag()!=null ? key_etag+" IS NULL OR " : "")+key_etag+"!=? OR "+key_content+"!=?)"; + whereArgs = new String[]{String.valueOf(id), DBStatus.VOID.getTitle(), remoteNote.getModified(DATE_FORMAT), remoteNote.getTitle(), remoteNote.isFavorite()?"1":"0", remoteNote.getCategory(), remoteNote.getEtag(), remoteNote.getContent()}; } int i = db.update(table_notes, values, whereClause, whereArgs); db.close(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java index 76203615d..a7b69e9fc 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java @@ -17,7 +17,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -267,20 +266,16 @@ private LoginStatus pullRemoteChanges() { Log.d(getClass().getSimpleName(), "pullRemoteChanges()"); LoginStatus status = null; try { - List localNotes = dbHelper.getNotes(); - Map localIDmap = new HashMap<>(); - for (DBNote note : localNotes) { - localIDmap.put(note.getRemoteId(), note.getId()); - } + Map idMap = dbHelper.getIdMap(); List remoteNotes = client.getNotes(); Set remoteIDs = new HashSet<>(); // pull remote changes: update or create each remote note for (CloudNote remoteNote : remoteNotes) { Log.d(getClass().getSimpleName(), " Process Remote Note: "+remoteNote); remoteIDs.add(remoteNote.getRemoteId()); - if(localIDmap.containsKey(remoteNote.getRemoteId())) { + if(idMap.containsKey(remoteNote.getRemoteId())) { Log.d(getClass().getSimpleName(), " ... found -> Update"); - dbHelper.updateNote(localIDmap.get(remoteNote.getRemoteId()), remoteNote, null); + dbHelper.updateNote(idMap.get(remoteNote.getRemoteId()), remoteNote, null); } else { Log.d(getClass().getSimpleName(), " ... create"); dbHelper.addNote(remoteNote); @@ -288,10 +283,10 @@ private LoginStatus pullRemoteChanges() { } Log.d(getClass().getSimpleName(), " Remove remotely deleted Notes (only those without local changes)"); // remove remotely deleted notes (only those without local changes) - for (DBNote note : localNotes) { - if(note.getStatus()==DBStatus.VOID && !remoteIDs.contains(note.getRemoteId())) { - Log.d(getClass().getSimpleName(), " ... remove "+note); - dbHelper.deleteNote(note.getId(), DBStatus.VOID); + for (Map.Entry entry : idMap.entrySet()) { + if(!remoteIDs.contains(entry.getKey())) { + Log.d(getClass().getSimpleName(), " ... remove "+entry.getValue()); + dbHelper.deleteNote(entry.getValue(), DBStatus.VOID); } } status = LoginStatus.OK; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java b/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java index f1b161d95..88323b090 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java @@ -31,6 +31,8 @@ public class NotesClient { private static final String key_title = "title"; private static final String key_content = "content"; 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 key_modified = "modified"; private static final String application_json = "application/json"; private String url = ""; @@ -44,28 +46,36 @@ public NotesClient(String url, String username, String password) { } private CloudNote getNoteFromJSON(JSONObject json) throws JSONException { - long noteId = 0; - String noteTitle = ""; - String noteContent = ""; - Calendar noteModified = null; - boolean noteFavorite = false; + long id = 0; + String title = ""; + String content = ""; + Calendar modified = null; + boolean favorite = false; + String category = null; + String etag = null; if (!json.isNull(key_id)) { - noteId = json.getLong(key_id); + id = json.getLong(key_id); } if (!json.isNull(key_title)) { - noteTitle = json.getString(key_title); + title = json.getString(key_title); } if (!json.isNull(key_content)) { - noteContent = json.getString(key_content); + content = json.getString(key_content); } if (!json.isNull(key_modified)) { - noteModified = GregorianCalendar.getInstance(); - noteModified.setTimeInMillis(json.getLong(key_modified) * 1000); + modified = GregorianCalendar.getInstance(); + modified.setTimeInMillis(json.getLong(key_modified) * 1000); } if (!json.isNull(key_favorite)) { - noteFavorite = json.getBoolean(key_favorite); + favorite = json.getBoolean(key_favorite); } - return new CloudNote(noteId, noteModified, noteTitle, noteContent, noteFavorite); + if (!json.isNull(key_category)) { + category = json.getString(key_category); + } + if (!json.isNull(key_etag)) { + etag = json.getString(key_etag); + } + return new CloudNote(id, modified, title, content, favorite, category, etag); } public List getNotes() throws JSONException, IOException { @@ -141,18 +151,17 @@ private String requestServer(String target, String method, JSONObject params) con.setRequestMethod(method); con.setRequestProperty( "Authorization", - "Basic " - + new String(Base64.encode((username + ":" - + password).getBytes(), Base64.NO_WRAP))); + "Basic " + Base64.encodeToString((username + ":" + password).getBytes(), Base64.NO_WRAP)); con.setConnectTimeout(10 * 1000); // 10 seconds Log.d(getClass().getSimpleName(), method + " " + targetURL); if (params != null) { + byte[] paramData = params.toString().getBytes(); Log.d(getClass().getSimpleName(), "Params: "+params); - con.setFixedLengthStreamingMode(params.toString().getBytes().length); + con.setFixedLengthStreamingMode(paramData.length); con.setRequestProperty("Content-Type", application_json); con.setDoOutput(true); OutputStream os = con.getOutputStream(); - os.write(params.toString().getBytes()); + os.write(paramData); os.flush(); os.close(); } diff --git a/app/src/main/res/layout/fragment_notes_list_note_item.xml b/app/src/main/res/layout/fragment_notes_list_note_item.xml index 735f65bc2..d86c31057 100644 --- a/app/src/main/res/layout/fragment_notes_list_note_item.xml +++ b/app/src/main/res/layout/fragment_notes_list_note_item.xml @@ -23,16 +23,30 @@ android:textSize="16sp" /> + +