mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 05:57:57 +01:00
Android: empty lists and loading error feedback
This commit is contained in:
parent
a84748f075
commit
1d08508e51
@ -20,7 +20,7 @@ public class MainApplication extends Application {
|
||||
JSONObject json = PreferenceUtil.getCachedJson(getApplicationContext(), PreferenceUtil.PREF_CACHED_USER_INFO_JSON);
|
||||
ApplicationContext.getInstance().setUserInfo(getApplicationContext(), json);
|
||||
|
||||
// TODO Error feedback (all REST request, even login)
|
||||
// TODO Documents list page loading feedback
|
||||
// TODO Fullscreen preview
|
||||
// TODO Caching preferences
|
||||
// TODO Edit sharing
|
||||
|
@ -16,10 +16,10 @@ import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.R;
|
||||
import com.sismics.docs.adapter.FilePagerAdapter;
|
||||
import com.sismics.docs.event.DocumentFullscreenEvent;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.model.application.ApplicationContext;
|
||||
import com.sismics.docs.resource.FileResource;
|
||||
import com.sismics.docs.util.PreferenceUtil;
|
||||
@ -139,14 +139,27 @@ public class DocumentActivity extends ActionBarActivity {
|
||||
sharedImageView.setVisibility(shared ? View.VISIBLE : View.GONE);
|
||||
|
||||
// Grab the attached files
|
||||
final View progressBar = findViewById(R.id.progressBar);
|
||||
final TextView filesEmptyView = (TextView) findViewById(R.id.filesEmptyView);
|
||||
fileViewPager = (ViewPager) findViewById(R.id.fileViewPager);
|
||||
fileViewPager.setOffscreenPageLimit(1);
|
||||
|
||||
FileResource.list(this, id, new JsonHttpResponseHandler() {
|
||||
@Override
|
||||
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
|
||||
fileViewPager = (ViewPager) findViewById(R.id.fileViewPager);
|
||||
fileViewPager.setOffscreenPageLimit(1);
|
||||
filePagerAdapter = new FilePagerAdapter(DocumentActivity.this, response.optJSONArray("files"));
|
||||
JSONArray files = response.optJSONArray("files");
|
||||
filePagerAdapter = new FilePagerAdapter(DocumentActivity.this, files);
|
||||
fileViewPager.setAdapter(filePagerAdapter);
|
||||
findViewById(R.id.progressBar).setVisibility(View.GONE);
|
||||
|
||||
progressBar.setVisibility(View.GONE);
|
||||
if (files.length() == 0) filesEmptyView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
|
||||
filesEmptyView.setText(R.string.error_loading_files);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
filesEmptyView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.androidquery.AQuery;
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.R;
|
||||
import com.sismics.docs.listener.CallbackListener;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.model.application.ApplicationContext;
|
||||
import com.sismics.docs.resource.UserResource;
|
||||
import com.sismics.docs.ui.form.Validator;
|
||||
@ -109,11 +109,11 @@ public class LoginActivity extends ActionBarActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
|
||||
public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
|
||||
loginForm.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
if (responseString != null && responseString.contains("\"ForbiddenError\"")) {
|
||||
if (responseBytes != null && new String(responseBytes).contains("\"ForbiddenError\"")) {
|
||||
DialogUtil.showOkDialog(LoginActivity.this, R.string.login_fail_title, R.string.login_fail);
|
||||
} else {
|
||||
DialogUtil.showOkDialog(LoginActivity.this, R.string.network_error_title, R.string.network_error);
|
||||
@ -167,9 +167,9 @@ public class LoginActivity extends ActionBarActivity {
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
|
||||
public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
|
||||
DialogUtil.showOkDialog(LoginActivity.this, R.string.network_error_title, R.string.network_error);
|
||||
loginForm.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.R;
|
||||
import com.sismics.docs.adapter.TagListAdapter;
|
||||
import com.sismics.docs.event.SearchEvent;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.model.application.ApplicationContext;
|
||||
import com.sismics.docs.provider.RecentSuggestionsProvider;
|
||||
import com.sismics.docs.resource.TagResource;
|
||||
@ -79,12 +79,20 @@ public class MainActivity extends ActionBarActivity {
|
||||
// Get tag list to fill the drawer
|
||||
final ListView tagListView = (ListView) findViewById(R.id.tagListView);
|
||||
final View tagProgressView = findViewById(R.id.tagProgressView);
|
||||
final View tagEmptyView = findViewById(R.id.tagEmptyView);
|
||||
final TextView tagEmptyView = (TextView) findViewById(R.id.tagEmptyView);
|
||||
tagListView.setEmptyView(tagProgressView);
|
||||
TagResource.stats(this, new JsonHttpResponseHandler() {
|
||||
@Override
|
||||
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
|
||||
tagListView.setAdapter(new TagListAdapter(response.optJSONArray("stats")));
|
||||
tagProgressView.setVisibility(View.GONE);
|
||||
tagListView.setEmptyView(tagEmptyView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
|
||||
tagEmptyView.setText(R.string.error_loading_tags);
|
||||
tagProgressView.setVisibility(View.GONE);
|
||||
tagListView.setEmptyView(tagEmptyView);
|
||||
}
|
||||
});
|
||||
|
@ -8,15 +8,18 @@ import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.R;
|
||||
import com.sismics.docs.activity.DocumentActivity;
|
||||
import com.sismics.docs.adapter.DocListAdapter;
|
||||
import com.sismics.docs.event.SearchEvent;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.listener.RecyclerItemClickListener;
|
||||
import com.sismics.docs.resource.DocumentResource;
|
||||
import com.sismics.docs.ui.view.DividerItemDecoration;
|
||||
import com.sismics.docs.ui.view.EmptyRecyclerView;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.json.JSONObject;
|
||||
@ -27,6 +30,11 @@ import de.greenrobot.event.EventBus;
|
||||
* @author bgamard.
|
||||
*/
|
||||
public class DocListFragment extends Fragment {
|
||||
/**
|
||||
* Recycler view.
|
||||
*/
|
||||
private EmptyRecyclerView recyclerView;
|
||||
|
||||
/**
|
||||
* Documents adapter.
|
||||
*/
|
||||
@ -46,7 +54,7 @@ public class DocListFragment extends Fragment {
|
||||
View view = inflater.inflate(R.layout.doc_list_fragment, container, false);
|
||||
|
||||
// Configure the RecyclerView
|
||||
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.docList);
|
||||
recyclerView = (EmptyRecyclerView) view.findViewById(R.id.docList);
|
||||
adapter = new DocListAdapter();
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
@ -87,14 +95,14 @@ public class DocListFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
if (!loading && totalItemCount - visibleItemCount <= firstVisibleItem + 3) {
|
||||
loadDocuments(false);
|
||||
loadDocuments(getView(), false);
|
||||
loading = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Grab the documents
|
||||
loadDocuments(true);
|
||||
loadDocuments(view, true);
|
||||
|
||||
EventBus.getDefault().register(this);
|
||||
return view;
|
||||
@ -113,30 +121,43 @@ public class DocListFragment extends Fragment {
|
||||
*/
|
||||
public void onEvent(SearchEvent event) {
|
||||
query = event.getQuery();
|
||||
loadDocuments(true);
|
||||
loadDocuments(getView(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the document list.
|
||||
*
|
||||
* @param view View
|
||||
* @param reset If true, reload the documents
|
||||
*/
|
||||
private void loadDocuments(final boolean reset) {
|
||||
private void loadDocuments(final View view, final boolean reset) {
|
||||
if (view == null) return;
|
||||
final View progressBar = view.findViewById(R.id.progressBar);
|
||||
final TextView documentsEmptyView = (TextView) view.findViewById(R.id.documentsEmptyView);
|
||||
|
||||
if (reset) {
|
||||
loading = true;
|
||||
previousTotal = 0;
|
||||
adapter.clearDocuments();
|
||||
if (getView() != null) {
|
||||
getView().findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
recyclerView.setEmptyView(progressBar);
|
||||
|
||||
DocumentResource.list(getActivity(), reset ? 0 : adapter.getItemCount(), query, new JsonHttpResponseHandler() {
|
||||
@Override
|
||||
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
|
||||
adapter.addDocuments(response.optJSONArray("documents"));
|
||||
if (getView() != null) {
|
||||
getView().findViewById(R.id.progressBar).setVisibility(View.GONE);
|
||||
documentsEmptyView.setText(R.string.no_documents);
|
||||
recyclerView.setEmptyView(documentsEmptyView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
|
||||
documentsEmptyView.setText(R.string.error_loading_documents);
|
||||
recyclerView.setEmptyView(documentsEmptyView);
|
||||
|
||||
if (!reset) {
|
||||
// We are loading a new page, so the empty view won't be visible, pop a toast
|
||||
Toast.makeText(getActivity(), R.string.error_loading_documents, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
Android Asynchronous Http Client
|
||||
Copyright (c) 2011 James Smith <james@loopj.com>
|
||||
http://loopj.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sismics.docs.listener;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.loopj.android.http.TextHttpResponseHandler;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
|
||||
/**
|
||||
* Used to intercept and handle the responses from requests made using {@link com.loopj.android.http.AsyncHttpClient}, with
|
||||
* automatic parsing into a {@link JSONObject} or {@link JSONArray}. <p> </p> This class is
|
||||
* designed to be passed to get, post, put and delete requests with the {@link #onSuccess(int,
|
||||
* org.apache.http.Header[], org.json.JSONArray)} or {@link #onSuccess(int,
|
||||
* org.apache.http.Header[], org.json.JSONObject)} methods anonymously overridden. <p> </p>
|
||||
* Additionally, you can override the other event methods from the parent class.
|
||||
*/
|
||||
public class JsonHttpResponseHandler extends TextHttpResponseHandler {
|
||||
|
||||
private static final String LOG_TAG = "JsonHttpResponseHandler";
|
||||
|
||||
/**
|
||||
* Creates new JsonHttpResponseHandler, with JSON String encoding UTF-8
|
||||
*/
|
||||
public JsonHttpResponseHandler() {
|
||||
super(DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new JsonHttpRespnseHandler with given JSON String encoding
|
||||
*
|
||||
* @param encoding String encoding to be used when parsing JSON
|
||||
*/
|
||||
public JsonHttpResponseHandler(String encoding) {
|
||||
super(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns when request succeeds
|
||||
*
|
||||
* @param statusCode http response status line
|
||||
* @param headers response headers if any
|
||||
* @param response parsed response if any
|
||||
*/
|
||||
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
|
||||
Log.w(LOG_TAG, "onSuccess(int, Header[], JSONObject) was not overriden, but callback was received");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns when request succeeds
|
||||
*
|
||||
* @param statusCode http response status line
|
||||
* @param headers response headers if any
|
||||
* @param response parsed response if any
|
||||
*/
|
||||
public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
|
||||
Log.w(LOG_TAG, "onSuccess(int, Header[], JSONArray) was not overriden, but callback was received");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns when request failed
|
||||
*
|
||||
* @param statusCode http response status line
|
||||
* @param headers response headers if any
|
||||
* @param throwable throwable describing the way request failed
|
||||
* @param errorResponse parsed response if any
|
||||
*/
|
||||
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
|
||||
Log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONObject) was not overriden, but callback was received", throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns when request failed
|
||||
*
|
||||
* @param statusCode http response status line
|
||||
* @param headers response headers if any
|
||||
* @param throwable throwable describing the way request failed
|
||||
* @param errorResponse parsed response if any
|
||||
*/
|
||||
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
|
||||
Log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONArray) was not overriden, but callback was received", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
|
||||
Log.w(LOG_TAG, "onFailure(int, Header[], String, Throwable) was not overriden, but callback was received", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(int statusCode, Header[] headers, String responseString) {
|
||||
Log.w(LOG_TAG, "onSuccess(int, Header[], String) was not overriden, but callback was received");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onSuccess(final int statusCode, final Header[] headers, final byte[] responseBytes) {
|
||||
if (statusCode != HttpStatus.SC_NO_CONTENT) {
|
||||
Runnable parser = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final Object jsonResponse = parseResponse(responseBytes);
|
||||
postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (jsonResponse instanceof JSONObject) {
|
||||
onSuccess(statusCode, headers, (JSONObject) jsonResponse);
|
||||
} else if (jsonResponse instanceof JSONArray) {
|
||||
onSuccess(statusCode, headers, (JSONArray) jsonResponse);
|
||||
} else if (jsonResponse instanceof String) {
|
||||
onFailure(statusCode, headers, (String) jsonResponse, new JSONException("Response cannot be parsed as JSON data"));
|
||||
} else {
|
||||
onFailure(statusCode, headers, new JSONException("Unexpected response type " + jsonResponse.getClass().getName()), (JSONObject) null);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} catch (final JSONException ex) {
|
||||
postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onFailure(statusCode, headers, ex, (JSONObject) null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!getUseSynchronousMode()) {
|
||||
new Thread(parser).start();
|
||||
} else {
|
||||
// In synchronous mode everything should be run on one thread
|
||||
parser.run();
|
||||
}
|
||||
} else {
|
||||
onSuccess(statusCode, headers, new JSONObject());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onFailure(final int statusCode, final Header[] headers, final byte[] responseBytes, final Throwable throwable) {
|
||||
if (responseBytes != null) {
|
||||
Runnable parser = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final Object jsonResponse = parseResponse(responseBytes);
|
||||
postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (jsonResponse instanceof JSONObject) {
|
||||
onFailure(statusCode, headers, throwable, (JSONObject) jsonResponse);
|
||||
} else if (jsonResponse instanceof JSONArray) {
|
||||
onFailure(statusCode, headers, throwable, (JSONArray) jsonResponse);
|
||||
} else if (jsonResponse instanceof String) {
|
||||
onFailure(statusCode, headers, (String) jsonResponse, throwable);
|
||||
} else {
|
||||
onFailure(statusCode, headers, new JSONException("Unexpected response type " + jsonResponse.getClass().getName()), (JSONObject) null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (final JSONException ex) {
|
||||
postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onFailure(statusCode, headers, ex, (JSONObject) null);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!getUseSynchronousMode()) {
|
||||
new Thread(parser).start();
|
||||
} else {
|
||||
// In synchronous mode everything should be run on one thread
|
||||
parser.run();
|
||||
}
|
||||
} else {
|
||||
Log.v(LOG_TAG, "response body is null, calling onFailure(Throwable, JSONObject)");
|
||||
onFailure(statusCode, headers, throwable, (JSONObject) null);
|
||||
}
|
||||
|
||||
// In all cases, call the default failure listener
|
||||
onAllFailure(statusCode, headers, responseBytes, throwable);
|
||||
}
|
||||
|
||||
public void onAllFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
|
||||
// All failures go there
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Object of type {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,
|
||||
* Double or {@link JSONObject#NULL}, see {@link org.json.JSONTokener#nextValue()}
|
||||
*
|
||||
* @param responseBody response bytes to be assembled in String and parsed as JSON
|
||||
* @return Object parsedResponse
|
||||
* @throws org.json.JSONException exception if thrown while parsing JSON
|
||||
*/
|
||||
protected Object parseResponse(byte[] responseBody) throws JSONException {
|
||||
if (null == responseBody)
|
||||
return null;
|
||||
Object result = null;
|
||||
//trim the string to prevent start with blank, and test if the string is valid JSON, because the parser don't do this :(. If JSON is not valid this will return null
|
||||
String jsonString = getResponseString(responseBody, getCharset());
|
||||
if (jsonString != null) {
|
||||
jsonString = jsonString.trim();
|
||||
if (jsonString.startsWith(UTF8_BOM)) {
|
||||
jsonString = jsonString.substring(1);
|
||||
}
|
||||
if (jsonString.startsWith("{") || jsonString.startsWith("[")) {
|
||||
result = new JSONTokener(jsonString).nextValue();
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
result = jsonString;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -3,8 +3,8 @@ package com.sismics.docs.model.application;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.listener.CallbackListener;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.resource.UserResource;
|
||||
import com.sismics.docs.util.PreferenceUtil;
|
||||
|
||||
|
@ -2,8 +2,8 @@ package com.sismics.docs.resource;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.loopj.android.http.RequestParams;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
|
||||
/**
|
||||
* Access to /document API.
|
||||
|
@ -2,7 +2,8 @@ package com.sismics.docs.resource;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Access to /file API.
|
||||
|
@ -2,7 +2,8 @@ package com.sismics.docs.resource;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Access to /tag API.
|
||||
|
@ -2,8 +2,8 @@ package com.sismics.docs.resource;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.loopj.android.http.JsonHttpResponseHandler;
|
||||
import com.loopj.android.http.RequestParams;
|
||||
import com.sismics.docs.listener.JsonHttpResponseHandler;
|
||||
|
||||
/**
|
||||
* Access to /user API.
|
||||
|
@ -0,0 +1,57 @@
|
||||
package com.sismics.docs.ui.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* RecyclerView with empty view support.
|
||||
* Thanks to https://gist.github.com/adelnizamutdinov/31c8f054d1af4588dc5c
|
||||
*
|
||||
* @author Nizamutdinov Adel
|
||||
*/
|
||||
public class EmptyRecyclerView extends RecyclerView {
|
||||
private View emptyView;
|
||||
|
||||
public EmptyRecyclerView(Context context) { super(context); }
|
||||
|
||||
public EmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); }
|
||||
|
||||
public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
void checkIfEmpty() {
|
||||
if (emptyView != null) {
|
||||
emptyView.setVisibility(getAdapter().getItemCount() > 0 ? GONE : VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
final AdapterDataObserver observer = new AdapterDataObserver() {
|
||||
@Override public void onChanged() {
|
||||
super.onChanged();
|
||||
checkIfEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
@Override public void setAdapter(Adapter adapter) {
|
||||
final Adapter oldAdapter = getAdapter();
|
||||
if (oldAdapter != null) {
|
||||
oldAdapter.unregisterAdapterDataObserver(observer);
|
||||
}
|
||||
super.setAdapter(adapter);
|
||||
if (adapter != null) {
|
||||
adapter.registerAdapterDataObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setEmptyView(View emptyView) {
|
||||
// Hide the current empty view
|
||||
if (this.emptyView != null) {
|
||||
this.emptyView.setVisibility(GONE);
|
||||
}
|
||||
this.emptyView = emptyView;
|
||||
checkIfEmpty();
|
||||
}
|
||||
}
|
@ -4,20 +4,30 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
<com.sismics.docs.ui.view.EmptyRecyclerView
|
||||
android:id="@+id/docList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical">
|
||||
|
||||
</android.support.v7.widget.RecyclerView>
|
||||
</com.sismics.docs.ui.view.EmptyRecyclerView>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/documentsEmptyView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/no_documents"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textSize="16sp"
|
||||
android:layout_centerInParent="true"/>
|
||||
|
||||
</RelativeLayout>
|
@ -94,6 +94,16 @@
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filesEmptyView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/no_files"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textSize="16sp"
|
||||
android:layout_centerInParent="true"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
@ -1,6 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Validation -->
|
||||
<string name="validate_error_email">Invalid email</string>
|
||||
<string name="validate_error_length_min">Too short (min. %d)</string>
|
||||
<string name="validate_error_length_max">Too long (max. %d)</string>
|
||||
<string name="validate_error_required">Required</string>
|
||||
<string name="validate_error_alphanumeric">Only letters and numbers</string>
|
||||
|
||||
<!-- App -->
|
||||
<string name="app_name">Sismics Docs</string>
|
||||
<string name="drawer_open">Open navigation drawer</string>
|
||||
<string name="drawer_close">Close navigation drawer</string>
|
||||
@ -28,12 +36,10 @@
|
||||
<string name="shared_documents">Shared documents</string>
|
||||
<string name="all_tags">All tags</string>
|
||||
<string name="no_tags">No tags</string>
|
||||
|
||||
<!-- Validation -->
|
||||
<string name="validate_error_email">Invalid email</string>
|
||||
<string name="validate_error_length_min">Too short (min. %d)</string>
|
||||
<string name="validate_error_length_max">Too long (max. %d)</string>
|
||||
<string name="validate_error_required">Required</string>
|
||||
<string name="validate_error_alphanumeric">Only letters and numbers</string>
|
||||
<string name="error_loading_tags">Error loading tags</string>
|
||||
<string name="no_documents">No documents</string>
|
||||
<string name="error_loading_documents">Error loading documents</string>
|
||||
<string name="no_files">No files</string>
|
||||
<string name="error_loading_files">Error loading files</string>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user