diff --git a/docs-android/app/app.iml b/docs-android/app/app.iml index 46bcd543..59404e26 100644 --- a/docs-android/app/app.iml +++ b/docs-android/app/app.iml @@ -98,15 +98,15 @@ + - - + + - diff --git a/docs-android/app/build.gradle b/docs-android/app/build.gradle index 31b88246..4e0567b0 100644 --- a/docs-android/app/build.gradle +++ b/docs-android/app/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0-rc1' + classpath 'com.android.tools.build:gradle:1.0.0' } } apply plugin: 'com.android.application' @@ -14,7 +14,7 @@ repositories { android { compileSdkVersion 21 - buildToolsVersion "21.1.1" + buildToolsVersion "21.1.2" defaultConfig { minSdkVersion 14 @@ -31,7 +31,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:appcompat-v7:21.0.2' + compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.android.support:recyclerview-v7:21.0.0' compile 'com.loopj.android:android-async-http:1.4.6' compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5' diff --git a/docs-android/app/src/main/java/com/sismics/docs/MainApplication.java b/docs-android/app/src/main/java/com/sismics/docs/MainApplication.java index 3506654f..f959913c 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/MainApplication.java +++ b/docs-android/app/src/main/java/com/sismics/docs/MainApplication.java @@ -21,7 +21,7 @@ public class MainApplication extends Application { ApplicationContext.getInstance().setUserInfo(getApplicationContext(), json); // TODO Fullscreen preview - // TODO Documents adding/editing + // TODO Document deleting // TODO Files adding/deleting super.onCreate(); diff --git a/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentEditActivity.java b/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentEditActivity.java index 889d7010..e59ec4a3 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentEditActivity.java +++ b/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentEditActivity.java @@ -1,5 +1,7 @@ package com.sismics.docs.activity; +import android.app.ProgressDialog; +import android.content.DialogInterface; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; @@ -8,22 +10,29 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.widget.EditText; import android.widget.Spinner; +import android.widget.Toast; import com.sismics.docs.R; import com.sismics.docs.adapter.LanguageAdapter; import com.sismics.docs.adapter.TagAutoCompleteAdapter; +import com.sismics.docs.event.DocumentAddEvent; import com.sismics.docs.event.DocumentEditEvent; +import com.sismics.docs.listener.JsonHttpResponseHandler; +import com.sismics.docs.resource.DocumentResource; import com.sismics.docs.ui.view.DatePickerView; import com.sismics.docs.ui.view.TagsCompleteTextView; import com.sismics.docs.util.PreferenceUtil; +import org.apache.http.Header; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import de.greenrobot.event.EventBus; @@ -96,6 +105,7 @@ public class DocumentEditActivity extends ActionBarActivity { tagsEditText.allowDuplicates(false); tagsEditText.setAdapter(new TagAutoCompleteAdapter(this, 0, tagList)); + // TODO Form validation // Fill the activity if (document == null) { datePickerView.setDate(new Date()); @@ -123,35 +133,83 @@ public class DocumentEditActivity extends ActionBarActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.save: - JSONObject outputDoc = new JSONObject(); - try { - if (document != null) { - outputDoc.putOpt("id", document.optString("id")); - outputDoc.putOpt("shared", document.optBoolean("shared")); - } - outputDoc.putOpt("title", titleEditText.getText().toString()); - outputDoc.putOpt("description", descriptionEditText.getText().toString()); - if (languageSpinner.getSelectedItem() != null) { - LanguageAdapter.Language language = (LanguageAdapter.Language) languageSpinner.getSelectedItem(); - outputDoc.putOpt("language", language.getId()); - } - if (datePickerView.getDate() != null) { - outputDoc.putOpt("create_date", datePickerView.getDate().getTime()); - } - JSONArray tags = new JSONArray(); - for (Object object : tagsEditText.getObjects()) { - if (object instanceof JSONObject) { - tags.put(object); - } - } - outputDoc.putOpt("tags", tags); - } catch (JSONException e) { - Log.e(DocumentEditActivity.class.getSimpleName(), "Error building JSON for document", e); + // Metadata + final String title = titleEditText.getText().toString(); + final String description = descriptionEditText.getText().toString(); + LanguageAdapter.Language language = (LanguageAdapter.Language) languageSpinner.getSelectedItem(); + final String langId = language.getId(); + final long createDate = datePickerView.getDate().getTime(); + Set tagIdList = new HashSet<>(); + for (Object object : tagsEditText.getObjects()) { + JSONObject tag = (JSONObject) object; + tagIdList.add(tag.optString("id")); } - EventBus.getDefault().post(new DocumentEditEvent(outputDoc)); - setResult(RESULT_OK); - finish(); + // Cancellable progress dialog + final ProgressDialog progressDialog = ProgressDialog.show(this, + getString(R.string.document_editing_title), + getString(R.string.document_editing_message), true, true, + new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + DocumentResource.cancel(DocumentEditActivity.this); + } + }); + + // Server callback + JsonHttpResponseHandler callback = new JsonHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, JSONObject response) { + // Build a fake document JSON to update the UI + final JSONObject outputDoc = new JSONObject(); + try { + if (document == null) { + outputDoc.putOpt("id", response.optString("id")); + outputDoc.putOpt("shared", false); + } else { + outputDoc.putOpt("id", document.optString("id")); + outputDoc.putOpt("shared", document.optBoolean("shared")); + } + outputDoc.putOpt("title", title); + outputDoc.putOpt("description", description); + outputDoc.putOpt("language", langId); + outputDoc.putOpt("create_date", createDate); + JSONArray tags = new JSONArray(); + for (Object object : tagsEditText.getObjects()) { + tags.put(object); + } + outputDoc.putOpt("tags", tags); + } catch (JSONException e) { + Log.e(DocumentEditActivity.class.getSimpleName(), "Error building JSON for document", e); + } + + // Fire the right event + if (document == null) { + EventBus.getDefault().post(new DocumentAddEvent(outputDoc)); + } else { + EventBus.getDefault().post(new DocumentEditEvent(outputDoc)); + } + setResult(RESULT_OK); + finish(); + } + + @Override + public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) { + Toast.makeText(DocumentEditActivity.this, R.string.error_editing_document, Toast.LENGTH_LONG).show(); + } + + @Override + public void onFinish() { + progressDialog.dismiss(); + } + }; + + // Actual server call + if (document == null) { + DocumentResource.add(this, title, description, tagIdList, langId, createDate, callback); + } else { + DocumentResource.edit(this, document.optString("id"), title, description, tagIdList, langId, createDate, callback); + } return true; case android.R.id.home: diff --git a/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentViewActivity.java b/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentViewActivity.java index 570b8d5b..b49e5042 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentViewActivity.java +++ b/docs-android/app/src/main/java/com/sismics/docs/activity/DocumentViewActivity.java @@ -118,6 +118,8 @@ public class DocumentViewActivity extends ActionBarActivity { * @param document Document in JSON format */ private void refreshDocument(JSONObject document) { + this.document = document; + String id = document.optString("id"); String title = document.optString("title"); String date = DateFormat.getDateFormat(this).format(new Date(document.optLong("create_date"))); diff --git a/docs-android/app/src/main/java/com/sismics/docs/event/DocumentAddEvent.java b/docs-android/app/src/main/java/com/sismics/docs/event/DocumentAddEvent.java new file mode 100644 index 00000000..244b68a5 --- /dev/null +++ b/docs-android/app/src/main/java/com/sismics/docs/event/DocumentAddEvent.java @@ -0,0 +1,33 @@ +package com.sismics.docs.event; + +import org.json.JSONObject; + +/** + * Document add event. + * + * @author bgamard. + */ +public class DocumentAddEvent { + /** + * Document. + */ + private JSONObject document; + + /** + * Create a document add event. + * + * @param document Document + */ + public DocumentAddEvent(JSONObject document) { + this.document = document; + } + + /** + * Getter of document. + * + * @return document + */ + public JSONObject getDocument() { + return document; + } +} diff --git a/docs-android/app/src/main/java/com/sismics/docs/fragment/DocListFragment.java b/docs-android/app/src/main/java/com/sismics/docs/fragment/DocListFragment.java index 8a0d1d09..3047e9c1 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/fragment/DocListFragment.java +++ b/docs-android/app/src/main/java/com/sismics/docs/fragment/DocListFragment.java @@ -17,6 +17,7 @@ import com.sismics.docs.R; import com.sismics.docs.activity.DocumentEditActivity; import com.sismics.docs.activity.DocumentViewActivity; import com.sismics.docs.adapter.DocListAdapter; +import com.sismics.docs.event.DocumentAddEvent; import com.sismics.docs.event.DocumentEditEvent; import com.sismics.docs.event.SearchEvent; import com.sismics.docs.listener.JsonHttpResponseHandler; @@ -44,6 +45,11 @@ public class DocListFragment extends Fragment { */ private String query; + /** + * Request code of adding document. + */ + private static final int REQUEST_CODE_ADD_DOCUMENT = 1; + // View cache private EmptyRecyclerView recyclerView; private SwipeRefreshLayout swipeRefreshLayout; @@ -87,9 +93,7 @@ public class DocListFragment extends Fragment { public void onItemClick(View view, int position) { JSONObject document = adapter.getItemAt(position); if (document != null) { - Intent intent = new Intent(getActivity(), DocumentViewActivity.class); - intent.putExtra("document", document.toString()); - startActivity(intent); + openDocument(document); } } })); @@ -123,7 +127,7 @@ public class DocListFragment extends Fragment { @Override public void onClick(View v) { Intent intent = new Intent(getActivity(), DocumentEditActivity.class); - startActivityForResult(intent, 1); + startActivityForResult(intent, REQUEST_CODE_ADD_DOCUMENT); } }); @@ -134,11 +138,6 @@ public class DocListFragment extends Fragment { return view; } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - // TODO Reload the documents after document creation and open it from data - } - @Override public void onDestroyView() { EventBus.getDefault().unregister(this); @@ -164,6 +163,30 @@ public class DocListFragment extends Fragment { adapter.updateDocument(event.getDocument()); } + /** + * A document add event has been fired. + * + * @param event Document add event + */ + public void onEvent(DocumentAddEvent event) { + // Refresh the list, maybe the new document fit in it + loadDocuments(getView(), true); + + // Open the newly created document + openDocument(event.getDocument()); + } + + /** + * Open a document. + * + * @param document Document to open + */ + private void openDocument(JSONObject document) { + Intent intent = new Intent(getActivity(), DocumentViewActivity.class); + intent.putExtra("document", document.toString()); + startActivity(intent); + } + /** * Refresh the document list. * diff --git a/docs-android/app/src/main/java/com/sismics/docs/resource/DocumentResource.java b/docs-android/app/src/main/java/com/sismics/docs/resource/DocumentResource.java index 502976ab..bff65450 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/resource/DocumentResource.java +++ b/docs-android/app/src/main/java/com/sismics/docs/resource/DocumentResource.java @@ -5,6 +5,8 @@ import android.content.Context; import com.loopj.android.http.RequestParams; import com.sismics.docs.listener.JsonHttpResponseHandler; +import java.util.Set; + /** * Access to /document API. * @@ -43,4 +45,62 @@ public class DocumentResource extends BaseResource { client.get(getApiUrl(context) + "/document/" + id, responseHandler); } + + /** + * PUT /document. + * + * @param context Context + * @param title Title + * @param description Description + * @param tagIdList Tags ID list + * @param language Language + * @param createDate Create date + * @param responseHandler Callback + */ + public static void add(Context context, String title, String description, + Set tagIdList, String language, long createDate, JsonHttpResponseHandler responseHandler) { + init(context); + + RequestParams params = new RequestParams(); + params.put("title", title); + params.put("description", description); + params.put("tags", tagIdList); + params.put("language", language); + params.put("create_date", createDate); + client.put(getApiUrl(context) + "/document", params, responseHandler); + } + + /** + * POST /document/id. + * + * @param context Context + * @param id ID + * @param title Title + * @param description Description + * @param tagIdList Tags ID list + * @param language Language + * @param createDate Create date + * @param responseHandler Callback + */ + public static void edit(Context context, String id, String title, String description, + Set tagIdList, String language, long createDate, JsonHttpResponseHandler responseHandler) { + init(context); + + RequestParams params = new RequestParams(); + params.put("title", title); + params.put("description", description); + params.put("tags", tagIdList); + params.put("language", language); + params.put("create_date", createDate); + client.post(getApiUrl(context) + "/document/" + id, params, responseHandler); + } + + /** + * Cancel pending requests. + * + * @param context Context + */ + public static void cancel(Context context) { + client.cancelRequests(context, true); + } } diff --git a/docs-android/app/src/main/java/com/sismics/docs/ui/view/DatePickerView.java b/docs-android/app/src/main/java/com/sismics/docs/ui/view/DatePickerView.java index 83475819..1ef99e81 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/ui/view/DatePickerView.java +++ b/docs-android/app/src/main/java/com/sismics/docs/ui/view/DatePickerView.java @@ -40,6 +40,9 @@ public class DatePickerView extends TextView implements DatePickerDialog.OnDateS @Override public void onClick(View v) { final Calendar calendar = Calendar.getInstance(); + if (date != null) { + calendar.setTime(date); + } new DatePickerDialog( DatePickerView.this.getContext(), DatePickerView.this, calendar.get(Calendar.YEAR), diff --git a/docs-android/app/src/main/res/values/strings.xml b/docs-android/app/src/main/res/values/strings.xml index 901f7512..bf00ac3a 100644 --- a/docs-android/app/src/main/res/values/strings.xml +++ b/docs-android/app/src/main/res/values/strings.xml @@ -76,6 +76,9 @@ Japanese Save Edit document + Network error, please try again + Please wait + Sending your data