Fix #146: don't autosave if the note isn't modified

New feature: cancel edit; refactoring of NotesClient; send local modified time to server
This commit is contained in:
korelstar 2016-10-26 11:32:20 +02:00 committed by Niedermann IT-Dienstleistungen
parent a57ecfeb4c
commit aa33b89927
7 changed files with 76 additions and 106 deletions

View file

@ -24,6 +24,7 @@ import it.niedermann.owncloud.notes.util.ICallback;
public class EditNoteActivity extends AppCompatActivity {
public static final String PARAM_NOTE = "note";
public static final String PARAM_ORIGINAL_NOTE = "original_note";
public static final String PARAM_NOTE_POSITION = "note_position";
private static final String LOG_TAG = "EditNote/SAVE";
@ -31,7 +32,7 @@ public class EditNoteActivity extends AppCompatActivity {
private static final long DELAY_AFTER_SYNC = 5000; // in ms
private EditText content = null;
private DBNote note = null;
private DBNote note, originalNote;
private int notePosition = 0;
private Timer timer, timerNextSync;
private boolean saveActive = false;
@ -44,11 +45,12 @@ public class EditNoteActivity extends AppCompatActivity {
setContentView(R.layout.activity_edit);
if (savedInstanceState == null) {
Log.d(getClass().getSimpleName(), "Starting from Intent");
note = (DBNote) getIntent().getSerializableExtra(PARAM_NOTE);
note = originalNote = (DBNote) getIntent().getSerializableExtra(PARAM_NOTE);
notePosition = getIntent().getIntExtra(PARAM_NOTE_POSITION, 0);
} else {
Log.d(getClass().getSimpleName(), "Starting from SavedState");
note = (DBNote) savedInstanceState.getSerializable(PARAM_NOTE);
originalNote = (DBNote) savedInstanceState.getSerializable(PARAM_ORIGINAL_NOTE);
notePosition = savedInstanceState.getInt(PARAM_NOTE_POSITION);
}
content = (EditText) findViewById(R.id.editContent);
@ -102,13 +104,14 @@ public class EditNoteActivity extends AppCompatActivity {
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putSerializable(PARAM_NOTE, note);
outState.putSerializable(PARAM_ORIGINAL_NOTE, originalNote);
outState.putInt(PARAM_NOTE_POSITION, notePosition);
super.onSaveInstanceState(outState);
}
@Override
public void onBackPressed() {
saveAndClose();
saveAndClose(true);
}
/**
@ -126,13 +129,17 @@ public class EditNoteActivity extends AppCompatActivity {
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
NoteSQLiteOpenHelper db;
switch (item.getItemId()) {
case android.R.id.home:
saveAndClose();
saveAndClose(true);
return true;
case R.id.menu_cancel:
Log.d(LOG_TAG, "CANCEL: changed: "+note);
Log.d(LOG_TAG, "CANCEL: original: "+originalNote);
note = db.updateNoteAndSync(originalNote, null, null);
saveAndClose(false);
return true;
case R.id.menu_delete:
db = new NoteSQLiteOpenHelper(this);
db.deleteNoteAndSync(note.getId());
Intent data = new Intent();
data.putExtra(PARAM_NOTE_POSITION, notePosition);
@ -168,7 +175,7 @@ public class EditNoteActivity extends AppCompatActivity {
/**
* Saves all changes and closes the Activity
*/
private void saveAndClose() {
private void saveAndClose(boolean save) {
content.setEnabled(false);
if(timer!=null) {
timer.cancel();
@ -178,7 +185,12 @@ public class EditNoteActivity extends AppCompatActivity {
timerNextSync.cancel();
timerNextSync = null;
}
saveData(null);
if(save) {
Log.d(LOG_TAG, "saveAndClose with SAVE");
saveData(null);
} else {
Log.d(LOG_TAG, "saveAndClose WITHOUT save");
}
Intent data = new Intent();
data.setAction(Intent.ACTION_VIEW);
data.putExtra(PARAM_NOTE, note);
@ -261,6 +273,7 @@ public class EditNoteActivity extends AppCompatActivity {
* @param callback
*/
private void saveData(ICallback callback) {
Log.d(LOG_TAG, "saveData()");
note = db.updateNoteAndSync(note, getContent(), callback);
}
}

View file

@ -243,13 +243,18 @@ public class NoteSQLiteOpenHelper extends SQLiteOpenHelper {
* The title is derived from the new content automatically, and modified date as well as DBStatus are updated, too -- if the content differs to the state in the database.
*
* @param oldNote Note to be changed
* @param newContent New content
* @param newContent New content. If this is <code>null</code>, then <code>oldNote</code> is saved again (useful for undoing changes).
* @param callback When the synchronization is finished, this callback will be invoked (optional).
* @return changed note if differs from database, otherwise the old note.
*/
public DBNote updateNoteAndSync(DBNote oldNote, String newContent, ICallback callback) {
debugPrintFullDB();
DBNote newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNoteTitle(newContent), newContent, DBStatus.LOCAL_EDITED);
DBNote newNote;
if(newContent==null) {
newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), DBStatus.LOCAL_EDITED);
} else {
newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNoteTitle(newContent), newContent, DBStatus.LOCAL_EDITED);
}
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(key_status, newNote.getStatus().getTitle());

View file

@ -222,13 +222,13 @@ public class NoteServerSyncHelper {
// if note is not new, try to edit it.
if (note.getRemoteId()>0) {
Log.d(getClass().getSimpleName(), " ...try to edit");
remoteNote = client.editNote(note.getRemoteId(), note.getContent());
remoteNote = client.editNote(note);
}
// However, the note may be deleted on the server meanwhile; or was never synchronized -> (re)create
// Please note, thas dbHelper.updateNote() realizes an optimistic conflict resolution, which is required for parallel changes of this Note from the UI.
if (remoteNote == null) {
Log.d(getClass().getSimpleName(), " ...Note does not exist on server -> (re)create");
remoteNote = client.createNote(note.getContent());
remoteNote = client.createNote(note);
dbHelper.updateNote(note.getId(), remoteNote, note);
} else {
dbHelper.updateNote(note.getId(), remoteNote, note);

View file

@ -41,41 +41,40 @@ public class NotesClient {
this.password = password;
}
public List<OwnCloudNote> getNotes() throws JSONException,
IOException {
List<OwnCloudNote> notesList = new ArrayList<>();
JSONArray notes = new JSONArray(requestServer("notes", METHOD_GET, null));
private OwnCloudNote getNoteFromJSON(JSONObject json) throws JSONException {
long noteId = 0;
String noteTitle = "";
String noteContent = "";
Calendar noteModified = null;
JSONObject currentItem;
for (int i = 0; i < notes.length(); i++) {
currentItem = notes.getJSONObject(i);
if (!json.isNull(key_id)) {
noteId = json.getLong(key_id);
}
if (!json.isNull(key_title)) {
noteTitle = json.getString(key_title);
}
if (!json.isNull(key_content)) {
noteContent = json.getString(key_content);
}
if (!json.isNull(key_modified)) {
noteModified = GregorianCalendar.getInstance();
noteModified
.setTimeInMillis(json.getLong(key_modified) * 1000);
}
return new OwnCloudNote(noteId, noteModified, noteTitle, noteContent);
}
if (!currentItem.isNull(key_id)) {
noteId = currentItem.getLong(key_id);
}
if (!currentItem.isNull(key_title)) {
noteTitle = currentItem.getString(key_title);
}
if (!currentItem.isNull(key_content)) {
noteContent = currentItem.getString(key_content);
}
if (!currentItem.isNull(key_modified)) {
noteModified = GregorianCalendar.getInstance();
noteModified
.setTimeInMillis(currentItem.getLong(key_modified) * 1000);
}
notesList
.add(new OwnCloudNote(noteId, noteModified, noteTitle, noteContent));
public List<OwnCloudNote> getNotes() throws JSONException, IOException {
List<OwnCloudNote> notesList = new ArrayList<>();
JSONArray notes = new JSONArray(requestServer("notes", METHOD_GET, null));
for (int i = 0; i < notes.length(); i++) {
JSONObject json = notes.getJSONObject(i);
notesList.add(getNoteFromJSON(json));
}
return notesList;
}
/**
* Fetches a Note by ID from Server
* TODO Maybe fetch only id, title and modified from server until a note has been opened?
*
* @param id long - ID of the wanted note
* @return Requested Note
@ -83,88 +82,33 @@ public class NotesClient {
* @throws IOException
*/
@SuppressWarnings("unused")
public OwnCloudNote getNoteById(long id) throws
JSONException, IOException {
long noteId = 0;
String noteTitle = "";
String noteContent = "";
Calendar noteModified = null;
JSONObject currentItem = new JSONObject(
requestServer("notes/" + id, METHOD_GET, null));
public OwnCloudNote getNoteById(long id) throws JSONException, IOException {
JSONObject json = new JSONObject(requestServer("notes/" + id, METHOD_GET, null));
return getNoteFromJSON(json);
}
if (!currentItem.isNull(key_id)) {
noteId = currentItem.getLong(key_id);
}
if (!currentItem.isNull(key_title)) {
noteTitle = currentItem.getString(key_title);
}
if (!currentItem.isNull(key_content)) {
noteContent = currentItem.getString(key_content);
}
if (!currentItem.isNull(key_modified)) {
noteModified = GregorianCalendar.getInstance();
noteModified
.setTimeInMillis(currentItem.getLong(key_modified) * 1000);
}
return new OwnCloudNote(noteId, noteModified, noteTitle, noteContent);
private OwnCloudNote putNote(OwnCloudNote note, String path) throws JSONException, IOException {
JSONObject paramObject = new JSONObject();
paramObject.accumulate(key_content, note.getContent());
paramObject.accumulate(key_modified, note.getModified().getTimeInMillis()/1000);
JSONObject json = new JSONObject(requestServer(path, METHOD_PUT, paramObject));
return getNoteFromJSON(json);
}
/**
* Creates a Note on the Server
*
* @param content String - Content of the new Note
* @param note {@link OwnCloudNote} - the new Note
* @return Created Note including generated Title, ID and lastModified-Date
* @throws JSONException
* @throws IOException
*/
public OwnCloudNote createNote(String content) throws
JSONException, IOException {
long noteId = 0;
String noteTitle = "";
String noteContent = "";
Calendar noteModified = null;
JSONObject paramObject = new JSONObject();
paramObject.accumulate(key_content, content);
JSONObject currentItem = new JSONObject(requestServer("notes", METHOD_POST,
paramObject));
if (!currentItem.isNull(key_id)) {
noteId = currentItem.getLong(key_id);
}
if (!currentItem.isNull(key_title)) {
noteTitle = currentItem.getString(key_title);
}
if (!currentItem.isNull(key_content)) {
noteContent = currentItem.getString(key_content);
}
if (!currentItem.isNull(key_modified)) {
noteModified = GregorianCalendar.getInstance();
noteModified
.setTimeInMillis(currentItem.getLong(key_modified) * 1000);
}
return new OwnCloudNote(noteId, noteModified, noteTitle, noteContent);
public OwnCloudNote createNote(OwnCloudNote note) throws JSONException, IOException {
return putNote(note, "notes");
}
public OwnCloudNote editNote(long noteId, String content)
throws JSONException, IOException {
String noteTitle = "";
Calendar noteModified = null;
JSONObject paramObject = new JSONObject();
paramObject.accumulate(key_content, content);
JSONObject currentItem = new JSONObject(requestServer(
"notes/" + noteId, METHOD_PUT, paramObject));
if (!currentItem.isNull(key_title)) {
noteTitle = currentItem.getString(key_title);
}
if (!currentItem.isNull(key_modified)) {
noteModified = GregorianCalendar.getInstance();
noteModified
.setTimeInMillis(currentItem.getLong(key_modified) * 1000);
}
return new OwnCloudNote(noteId, noteModified, noteTitle, content);
public OwnCloudNote editNote(OwnCloudNote note) throws JSONException, IOException {
return putNote(note, "notes/" + note.getRemoteId());
}
public void deleteNote(long noteId) throws

View file

@ -20,6 +20,12 @@
android:orderInCategory="110"
app:showAsAction="never"
android:title="@string/menu_copy"/-->
<item
android:id="@+id/menu_cancel"
android:icon="@drawable/ic_action_cancel"
android:orderInCategory="110"
android:title="@string/menu_cancel"
app:showAsAction="never" />
<item
android:id="@+id/menu_delete"
android:icon="@drawable/ic_action_delete"

View file

@ -16,6 +16,7 @@
<string name="menu_delete">Löschen</string>
<string name="menu_copy">Kopieren</string>
<string name="menu_edit">Bearbeiten</string>
<string name="menu_cancel">Abbrechen</string>
<string name="menu_preview">Vorschau</string>
<string name="menu_share">Teilen</string>
<string name="menu_about">Über</string>

View file

@ -17,6 +17,7 @@
<string name="menu_delete">Delete</string>
<string name="menu_copy">Copy</string>
<string name="menu_edit">Edit</string>
<string name="menu_cancel">Cancel</string>
<string name="menu_preview">Preview</string>
<string name="menu_share">Share</string>
<string name="menu_about">About</string>